day17-集合框架(HashSet/TreeSet)

17.01_HashSet存储字符串并遍历

  • A:Set集合概述及特点
    public class HashSet<E>extends AbstractSet<E>implements Set<E>, Cloneable, Serializable
// Set集合,无索引,无重复数据,无序(存储不一致)
HashSet<String> set = new HashSet<>();
set.add("a");
set.add("a");         //因为set集合不能存储重复数据,所以这里存储失败,返回false
set.add("xxoo");

for (String string : set) {    //迭代,增强for
    System.out.println(string);
}

17.02_HashSet存储自定义对象保证元素唯一性

  • 核心:重写自定义对象的hashCode()equals()方法
  • 自动生成即可。Eclipse自动生成hashCode和equals方法
@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + age;
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    return result;
}
为什么Eclipe自动生成hashCode会选择31
1.31是一个质数,质数能被1和自身整除,减少重复性
2.31这个数不大也不小
3.31这个数好算,2的五次方-1,2向左移动5次减1

17.04_HashSet如何保证元素唯一性的原理

  • 1.HashSet原理
    • 我们使用Set集合都是需要去掉重复元素的, 如果在存储的时候逐个equals()比较, 效率较低,哈希算法提高了去重复的效率, 降低了使用equals()方法的次数
    • HashSet调用add()方法存储对象的时候, 先调用对象的hashCode()方法得到一个哈希值, 然后在集合中查找是否有哈希值相同的对象
      • 如果没有哈希值相同的对象就直接存入集合
      • 如果有哈希值相同的对象, 就和哈希值相同的对象逐个进行equals()比较,比较结果为false就存入, true则不存
  • 2.将自定义类的对象存入HashSet去重复
    • 类中必须重写hashCode()equals()方法
    • hashCode(): 属性相同的对象返回值必须相同, 属性不同的返回值尽量不同(提高效率)
    • equals(): 属性相同返回true, 属性不同返回false,返回false的时候存储

17.05_LinkedHashSet的概述和使用

//LinkedHashSet 底层是链表实现的,是Set集合中唯一一个能保证怎么存就怎么取的集合对象
//虽然存顺序和取顺序是一样的, 但是并没有索引
//因为HashSet的子类,所以也能保证元素是唯一的
LinkedHashSet<String> link = new LinkedHashSet<>();
link.add("a");
link.add("a");
link.add("b");
System.out.println(link);    // [a,b]

17.06_产生10个1-20之间的随机数要求随机数不能重复

需求:编写一个程序,获取10个1至20的随机数,要求随机数不能重复。并把最终的随机数输出到控制台。

HashSet<Integer> set = new HashSet<>();
Random random = new Random();
while (10 > set.size()) {
    set.add(random.nextInt(20) + 1);  //注意这里的随机数方法, +1是因为随机数方法是前闭后开的
}
System.out.println(set);    //这里也可以使用foreach循环输出

17.07_集合框架(练习)

  • 使用Scanner从键盘读取一行输入,去掉其中重复字符, 打印出不同的那些字符
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
sc.close();
char[] arr = str.toCharArray();     //将字符串转换成字符数组
LinkedHashSet<Character> set = new LinkedHashSet<>();  //创建LinkedHashSet集合对象(为了跟输入顺序一致)
for (char c : arr) {
    set.add(c);
}
System.out.println(set);   //输入xxoo123,输出[x,o,1,2,3]

17.08_集合框架(练习)

// 将集合中的重复元素去掉
public static void getSingle(List<String> list) {
     LinkedHashSet<String> lhs = new LinkedHashSet<>();
     lhs.addAll(list);    //将list集合中的所有元素添加到lhs
     list.clear();       //清空原集合
     list.addAll(lhs);   //将去除重复的元素添回到list中
}

17.09_TreeSet存储Integer类型的元素并遍历

// 1.TreeSet能保证数据唯一,2.TreeSet是用来对元素排序的
TreeSet<Integer> ts = new TreeSet<>();
ts.add(3);
ts.add(2);
ts.add(2);
ts.add(1);
System.out.println(ts);   //输出 [1, 2, 3]

17.10_TreeSet存储自定义对象

TreeSet<Person> ts = new TreeSet<>();
ts.add(new Person("我日", 20));
ts.add(new Person("我2", 22));
ts.add(new Person("我xo", 80));

System.out.println(ts);

// 1. 直接存储,会运行报错
// 2. 想要不报错,Person类必须实现Comparable<T>接口
// 3.Comparable<T>接口的规律如下:
@Override
public int compareTo(Person o) {
     //当compareTo方法返回0 ,集合只有一个元素
     //当compareTo方法返回正数,集合怎么存,就怎么取
     //当compareTo方法返回负数,集合就会倒序
     int num = this.age - o.age ;  //年龄为主要条件,年龄一样比较姓名
     return num == 0 ? this.name.compareTo(o.name) : num;
}

17.11_TreeSet保证元素唯一和自然排序的原理和图解

TreeSet.png

17.12_TreeSet存储自定义对象并遍历练习1

TreeSet存储自定义对象并遍历练习1(按照姓名排序)
关键-->Person的compareTo方法
public int compareTo(Person o) {
     int num = this.name.compareTo(o.name);  //姓名是主要条件 
     return num == 0 ? this.age - o.age : num; //年龄是次要条件
}

// 字符串的比较,是比较字符串每个字符的Unicode值

17.14_TreeSet保证元素唯一和比较器排序的原理及代码实现

//匿名类 实现构造器
Comparator<String> com = new Comparator<String>() {
     @Override
     public int compare(String o1, String o2) {
          // 安装字符串长度比较
          int num = o1.length() - o2.length();
          return num == 0 ? o1.compareTo(o2) : num; //长度相同比较内容
     }
};

// 比较器排序  TreeSet有个传入构造器的构造方法
TreeSet<String> ts = new TreeSet<>(com);
ts.add("aabbcc");
ts.add("0125");
ts.add("c");
System.out.println(ts);

17.15_TreeSet原理

  • TreeSet是用来排序的, 可以指定一个顺序, 对象存入之后会按照指定的顺序排列
  • a.自然顺序(Comparable)
- TreeSet类的add()方法中会把存入的对象提升为Comparable类型
- 调用对象的compareTo()方法和集合中的对象比较
- 根据compareTo()方法返回的结果进行存储
  • b.比较器顺序(Comparator)
- 创建TreeSet的时候可以制定 一个Comparator
- 如果传入了Comparator的子类对象, 那么TreeSet就会按照比较器中的顺序排序
- add()方法内部会自动调用Comparator接口中compare()方法排序
- 调用的对象是compare方法的第一个参数,集合中的对象是compare方法的第二个参数
  • c.两种方式的区别
- TreeSet构造函数什么都不传, 默认按照类中Comparable的顺序(没有就报错ClassCastException)
- TreeSet如果传入Comparator, 就优先按照Comparator

17.16_集合框架(练习一)

  • 在一个集合中存储了无序并且重复的字符串,定义一个方法,让其有序(字典顺序),而且还不能去除重复
ArrayList<String> list = new ArrayList<>();
list.add("ccc");
list.add("ccc");
list.add("aaa");
list.add("aaa");
list.add("bbb");
list.add("ddd");
list.add("ddd");

Comparator<String> com = new Comparator<String>() {  //匿名构造器
     @Override
     public int compare(String s1, String s2) {
          int num = s1.compareTo(s2);
          return num == 0 ? 1 : num;  //如果内容一样返回一个不为0的数字即可
     }
};

TreeSet<String> set = new TreeSet<>(com);
set.addAll(list);  //讲ArrayList的元素,一次性添加到TreeSet里面

list.clear();  //清空原来的ArrayList
list.addAll(set); //再将排序后的添加来
System.out.println(list);

17.17_集合框架(练习二)

  • 从键盘接收一个字符串, 程序对其中所有字符进行排序,例如键盘输入: helloitcast程序打印:acehillostt
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
sc.close();
char[] arr = str.toCharArray();  //转为char[]数组

// 方法一
Arrays.sort(arr);           // Arrays排序
System.out.println(arr);    // 搞定

// 方法二 (使用TreeSet)
Comparator<Character> com = new Comparator<Character>() {
     @Override
     public int compare(Character c1, Character c2) {
          int temp = c1 - c2;     //自动拆箱
          return temp == 0 ? 1 : temp;
     }
};

TreeSet<Character> set = new TreeSet<>(com);
for (Character ch : arr) {  //其实这里Character和char都可以,自动装箱
     set.add(ch);
}
str = "";
for (Character character : set) {   //转字符串
     str += character;
}
System.out.println(str);

17.18_集合框架(练习三)

  • 程序启动后, 可以从键盘输入接收多个整数, 直到输入quit时结束输入. 把所有输入的整数倒序排列打印.
Scanner sc = new Scanner(System.in);

TreeSet<Integer> set = new TreeSet<>(new Comparator<Integer>() { //匿名类
     @Override 
     public int compare(Integer t1, Integer t2) {
          int num = t2 - t1 ;  //自动拆箱   使用t2.compareTo(t1)也可以
          return num == 0 ? 1 : num;
     }
});

while (true) {
     String str = sc.nextLine();
     //如果字符串常量和变量比较,常量放前面,这样不会出现空指针异常,变量里面可能存储null
     if ("quit".equals(str)) break; 
     set.add(Integer.valueOf(str));  //两个方法都可以:Integer.parseInt(str);
     // 其实这里应该加异常处理,后面会异常再讲
}

sc.close();
System.out.println(set);

17.19_键盘录入学生信息按照总分排序后输出在控制台

  • 需求:键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台。
Scanner sc = new Scanner(System.in);
System.out.println("请输入5个学生成绩格式是:(姓名,语文成绩,数学成绩,英语成绩)");
TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
     @Override
     public int compare(Student s1, Student s2) {
          int num = s2.getSum() - s1.getSum();  //根据学生的总成绩降序排列
          return num == 0 ? 1 : num;
     }
});

while(ts.size() < 5) {
     String line = sc.nextLine();
     try {
          String[] arr = line.split(",");  //分割字符串,方法需要记住!
          int chinese = Integer.parseInt(arr[1]);                //转换语文成绩
          int math = Integer.parseInt(arr[2]);                   //转换数学成绩
          int english = Integer.parseInt(arr[3]);                //转换英语成绩
          ts.add(new Student(arr[0], chinese, math, english));
     } catch (Exception e) {
          System.out.println("录入格式有误,输入5个学生成绩格式是:(姓名,语文成绩,数学成绩,英语成绩");
     }
}
sc.close();
System.out.println(ts);

17.20_day17总结

  • 1.List 集合遍历方法:
    • a.普通for循环, 使用get()逐个获取元素
    • b.调用iterator()方法得到Iterator, 使用hasNext()next()方法
    • c.增强for循环, 只要可以使用Iterator的类都可以用
    • d.Vector集合可以使用EnumerationhasMoreElements()nextElement()方法
  • 2.Set集合遍历方法
    • a.调用iterator()方法得到Iterator, 使用hasNext()next()方法
    • b.增强for循环, 只要可以使用Iterator的类都可以用
  • 3.普通for循环,迭代器,增强for循环是否可以在遍历的过程中删除
    • 普通for循环 --> 能 --> i(索引)需要--
    • 迭代器 --> 能,但是需要使用迭代器的删除方法
    • 增强for循环 --> 不能

END。
我是小侯爷。
在魔都艰苦奋斗,白天是上班族,晚上是知识服务工作者。
如果读完觉得有收获的话,记得关注和点赞哦。
非要打赏的话,我也是不会拒绝的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,616评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,020评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,078评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,040评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,154评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,265评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,298评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,072评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,491评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,795评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,970评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,654评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,272评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,985评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,815评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,852评论 2 351

推荐阅读更多精彩内容