美文网首页
day17-集合框架(HashSet/TreeSet)

day17-集合框架(HashSet/TreeSet)

作者: 苦笑男神 | 来源:发表于2017-01-23 16:44 被阅读99次

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

    相关文章

      网友评论

          本文标题:day17-集合框架(HashSet/TreeSet)

          本文链接:https://www.haomeiwen.com/subject/htknbttx.html