• 大数据之路week02 Collection 集合体系收尾(Set)


    1、Set集合(理解)

      (1)Set集合的特点

        无序,唯一。

      (2)HashSet集合(掌握)

        A: 底层数据结构是哈希表(是一个元素为链表的数组)

        B: 哈希表底层依赖两个方法: hashCode() 和 equals()

          执行顺序:

            首先比较哈希值是否相同

              相同:继续执行equals()方法

                返回true:元素重复了,不添加

                返回false:直接把元素添加到集合

              不同:就直接把元素添加到集合

    1、人的类

     1 package com.wyh.hashSet;
     2 
     3 /** 
     4 * @author WYH
     5 * @version 2019年11月17日 上午9:21:02
     6 */
     7 public class Person {
     8     private String name;
     9     private int age;
    10     
    11     public Person(String name, int age) {
    12         super();
    13         this.name = name;
    14         this.age = age;
    15     }
    16     public Person() {
    17         super();
    18         // TODO Auto-generated constructor stub
    19     }
    20     
    21     public String getName() {
    22         return name;
    23     }
    24     public void setName(String name) {
    25         this.name = name;
    26     }
    27     public int getAge() {
    28         return age;
    29     }
    30     public void setAge(int age) {
    31         this.age = age;
    32     }
    33     
    34     //重写hashCode方法和equals方法
    35     @Override
    36     public int hashCode() {
    37         final int prime = 31;
    38         int result = 1;
    39         result = prime * result + age;
    40         result = prime * result + ((name == null) ? 0 : name.hashCode());
    41         return result;
    42     }
    43     @Override
    44     public boolean equals(Object obj) {
    45         if (this == obj)
    46             return true;
    47         if (obj == null)
    48             return false;
    49         if (getClass() != obj.getClass())
    50             return false;
    51         Person other = (Person) obj;
    52         if (age != other.age)
    53             return false;
    54         if (name == null) {
    55             if (other.name != null)
    56                 return false;
    57         } else if (!name.equals(other.name))
    58             return false;
    59         return true;
    60     }
    61     
    62 
    63 }

    2、测试类:

     1 package com.wyh.hashSet;
     2 
     3 import java.util.HashSet;
     4 
     5 /** 
     6 * @author WYH
     7 * @version 2019年11月17日 上午9:21:16
     8 */
     9 public class HashSetDemo01 {
    10     public static void main(String[] args) {
    11         //创建HashSet集合
    12         HashSet<Person> hs = new HashSet<Person>();
    13         
    14         //创建Person类
    15         Person p1 = new Person("小虎",22);
    16         Person p2 = new Person("小强",23);
    17         Person p3 = new Person("小虎",22);
    18         Person p4 = new Person("小美",21);
    19         Person p5 = new Person("小雪",21);
    20         
    21         //将对象添加到HashSet中去
    22         hs.add(p1);
    23         hs.add(p2);
    24         hs.add(p3);
    25         hs.add(p4);
    26         hs.add(p5);
    27         
    28         
    29         //遍历
    30         for(Person p : hs) {
    31             System.out.println(p.getName()+"---"+p.getAge());
    32             
    33             
    34         }
    35     }
    36 
    37 }

    3、如下图,如果不重写hashCode()方法和equals()方法,运行结果,可以运行不报错,但是重复的元素也加入了。

    4、重写后:

        C:如何保证元素的唯一性呢?

          由hashCode()和equals()保证的(如下图,流程)

        D:开发的时候,代码非常的简单,自动生成即可。

        E:HashSet存储字符串并遍历

     1 package com.wyh.set;
     2 
     3 import java.util.HashSet;
     4 
     5 /** 
     6 * @author WYH
     7 * @version 2019年11月16日 下午7:42:24
     8 * 
     9 * HashSet在存储字符串的时候,为什么只存储相同的字符串只存储一个呢?
    10 * 通过查看add方法的源码,我们发现这个方法的底层方法是依赖两个方法,hashCode()和equals() 
    11 * 
    12 * 
    13 */
    14 public class HashSetDemo01 {
    15     public static void main(String[] args) {
    16         HashSet<String> hs = new HashSet<String>();
    17         
    18         hs.add("Hello");
    19         hs.add("World");
    20         hs.add("Java");
    21         hs.add("World");
    22         
    23         for(String s : hs) {
    24             System.out.println(s);
    25         }
    26     
    27     }
    28 
    29 }

        F:HashSet存储自定义对象并遍历(对象的成员变量值相同即为同一个元素)

      (3)TreeSet集合

        A:底层数据结构是红黑树(是一个自平衡的二叉树)

        B:  保证元素的排序方式

          a: 自然排序(元素具备比较性)

            让元素所属的类实现Comparable接口(难点,需求会给出主要条件,但是需要我们分析次要条件,例如 需求是根据年龄的长度进行排序,但是我们还要考虑姓名的长度和内容)

    学生类:

     1 package com.wyh.treeSet;
     2 
     3 /** 
     4 * @author WYH
     5 * @version 2019年11月17日 上午11:13:45
     6 */
     7 public class Student2 implements Comparable<Student2>{
     8     private String name;
     9     private int age;
    10     public Student2(String name, int age) {
    11         super();
    12         this.name = name;
    13         this.age = age;
    14     }
    15     public Student2() {
    16         super();
    17         // TODO Auto-generated constructor stub
    18     }
    19     public String getName() {
    20         return name;
    21     }
    22     public void setName(String name) {
    23         this.name = name;
    24     }
    25     public int getAge() {
    26         return age;
    27     }
    28     public void setAge(int age) {
    29         this.age = age;
    30     }
    31     @Override
    32     public int compareTo(Student2 s) {
    33         int num = this.name.length() - s.name.length();
    34         //次要条件1 姓名长度一样,内容不一定一样
    35         int num2 = num == 0 ? (this.name.compareTo(s.name)) : num;
    36         //次要条件2 姓名长度和内容一样,年龄不一定一样
    37         int num3 = num2 == 0 ? this.age - s.age : num2;
    38         return num3;
    39         
    40     }
    41     
    42     
    43     
    44     
    45 }

    测试类:

    如果不重写自然排序方法,就会报错,因为没有给定如何排序,也没有保证唯一性
    // java.lang.ClassCastException: com.wyh.treeSet.Student cannot be cast to
    // java.lang.Comparable

     1 package com.wyh.treeSet;
     2 
     3 import java.util.TreeSet;
     4 
     5 /**
     6  * @author WYH
     7  * @version 2019年11月17日 下午2:27:13
     8  * 
     9  *          根据年龄的长度进行排序
    10  */
    11 public class TreeSetDemo03 {
    12     public static void main(String[] args) {
    13         TreeSet<Student2> ts = new TreeSet<Student2>();
    14 
    15         // 创建学生对象
    16         Student2 s1 = new Student2("王友虎", 22);
    17         Student2 s2 = new Student2("赵以浩", 24);
    18         Student2 s3 = new Student2("齐博源", 21);
    19         Student2 s4 = new Student2("李先锋", 23);
    20         Student2 s5 = new Student2("李宏灿", 22);
    21         Student2 s6 = new Student2("薛长城", 23);
    22         Student2 s7 = new Student2("黄天祥", 24);
    23         Student2 s8 = new Student2("王友虎", 23);
    24 
    25         // 添加到TreeSet中
    26         ts.add(s1);
    27         ts.add(s2);
    28         ts.add(s3);
    29         ts.add(s4);
    30         ts.add(s5);
    31         ts.add(s6);
    32         ts.add(s7);
    33         ts.add(s8);
    34 
    35         // 遍历
    36         // 如果不重写自然排序方法,就会报错,因为没有给定如何排序,也没有保证唯一性
    37         // java.lang.ClassCastException: com.wyh.treeSet.Student cannot be cast to
    38         // java.lang.Comparable
    39         for (Student2 s : ts) {
    40             System.out.println(s.getName() + "---" + s.getAge());
    41         }
    42 
    43     }
    44 
    45 

          b: 比较器排序(集合具备比较性)

            让集合构造方法接收Comparator的实现类对象(但是我们一般用匿名内部类的方式实现)

    方式1、我们不用内部类的方式实现:

    定义一个类实现Comparator<T> 接口,重写compare方法:

     1 package com.wyh.treeSet2;
     2 
     3 import java.util.Comparator;
     4 
     5 /** 
     6 * @author WYH
     7 * @version 2019年11月17日 下午2:48:22
     8 */
     9 public class MyComparator implements Comparator<Student2> {
    10 
    11     @Override
    12     public int compare(Student2 s1, Student2 s2) {
    13         int num = s1.getName().length() - s2.getName().length();
    14         int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
    15         int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
    16         return num3;
    17     }
    18 
    19     
    20 
    21 }

    测试类:

     1 package com.wyh.treeSet2;
     2 
     3 import java.util.Comparator;
     4 import java.util.TreeSet;
     5 
     6 /**
     7  * @author WYH
     8  * @version 2019年11月17日 下午2:27:13
     9  * 
    10  *          根据年龄的长度进行排序
    11  */
    12 public class TreeSetDemo03 {
    13     public static void main(String[] args) {
    14 //        TreeSet<Student2> ts = new TreeSet<Student2>();
    15         TreeSet<Student2> ts = new TreeSet<Student2>(new MyComparator());
    16         
    17         //如果一个方法的参数是接口,那么真正要的是实现这个接口的实现类
    18         //匿名内部类可以是实现
    19        /* TreeSet<Student2> ts = new TreeSet<Student2>(new Comparator<Student2>(){
    20             @Override
    21             public int compare(Student2 s1, Student2 s2) {
    22                 int num = s1.getName().length() - s2.getName().length();
    23                 int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
    24                 int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
    25                 return num3;
    26             }
    27         });*/
    28  
    29         // 创建学生对象
    30         Student2 s1 = new Student2("王友虎", 22);
    31         Student2 s2 = new Student2("赵以浩", 24);
    32         Student2 s3 = new Student2("齐博源", 21);
    33         Student2 s4 = new Student2("李先锋", 23);
    34         Student2 s5 = new Student2("李宏灿", 22);
    35         Student2 s6 = new Student2("薛长城", 23);
    36         Student2 s7 = new Student2("黄天祥", 24);
    37         Student2 s8 = new Student2("王友虎", 23);
    38 
    39         // 添加到TreeSet中
    40         ts.add(s1);
    41         ts.add(s2);
    42         ts.add(s3);
    43         ts.add(s4);
    44         ts.add(s5);
    45         ts.add(s6);
    46         ts.add(s7);
    47         ts.add(s8);
    48 
    49         // 遍历
    50         // 如果不重写自然排序方法,就会报错,因为没有给定如何排序,也没有保证唯一性
    51         // java.lang.ClassCastException: com.wyh.treeSet.Student cannot be cast to
    52         // java.lang.Comparable
    53         for (Student2 s : ts) {
    54             System.out.println(s.getName() + "---" + s.getAge());
    55         }
    56 
    57     }
    58 
    59 }

    方式2、用匿名内部类的方式实现:

     1 package com.wyh.treeSet2;
     2 
     3 import java.util.Comparator;
     4 import java.util.TreeSet;
     5 
     6 /**
     7  * @author WYH
     8  * @version 2019年11月17日 下午2:27:13
     9  * 
    10  *          根据年龄的长度进行排序
    11  */
    12 public class TreeSetDemo03 {
    13     public static void main(String[] args) {
    14 //        TreeSet<Student2> ts = new TreeSet<Student2>();
    15 //        TreeSet<Student2> ts = new TreeSet<Student2>(new MyComparator());
    16         
    17         //如果一个方法的参数是接口,那么真正要的是实现这个接口的实现类
    18         //匿名内部类可以是实现
    19         TreeSet<Student2> ts = new TreeSet<Student2>(new Comparator<Student2>(){
    20             @Override
    21             public int compare(Student2 s1, Student2 s2) {
    22                 int num = s1.getName().length() - s2.getName().length();
    23                 int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
    24                 int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
    25                 return num3;
    26             }
    27         });
    28  
    29         // 创建学生对象
    30         Student2 s1 = new Student2("王友虎", 22);
    31         Student2 s2 = new Student2("赵以浩", 24);
    32         Student2 s3 = new Student2("齐博源", 21);
    33         Student2 s4 = new Student2("李先锋", 23);
    34         Student2 s5 = new Student2("李宏灿", 22);
    35         Student2 s6 = new Student2("薛长城", 23);
    36         Student2 s7 = new Student2("黄天祥", 24);
    37         Student2 s8 = new Student2("王友虎", 23);
    38 
    39         // 添加到TreeSet中
    40         ts.add(s1);
    41         ts.add(s2);
    42         ts.add(s3);
    43         ts.add(s4);
    44         ts.add(s5);
    45         ts.add(s6);
    46         ts.add(s7);
    47         ts.add(s8);
    48 
    49         // 遍历
    50         // 如果不重写自然排序方法,就会报错,因为没有给定如何排序,也没有保证唯一性
    51         // java.lang.ClassCastException: com.wyh.treeSet.Student cannot be cast to
    52         // java.lang.Comparable
    53         for (Student2 s : ts) {
    54             System.out.println(s.getName() + "---" + s.getAge());
    55         }
    56 
    57     }
    58 
    59 }

      (4)案例:

        A: 获取无重复的随机数(HashSet实现)

     1 package com.wyh.HashSet_random;
     2 
     3 import java.util.Arrays;
     4 import java.util.HashSet;
     5 import java.util.Random;
     6 
     7 /** 
     8 * @author WYH
     9 * @version 2019年11月17日 下午3:14:10
    10 * 
    11 * 实现10个1-20的随机数
    12 * 
    13 * 
    14 * 
    15 */
    16 public class HashSet_random_Demo {
    17     public static void main(String[] args) {
    18         //创建随机数对象
    19         Random r = new Random();
    20         
    21         //创建HashSet集合
    22         HashSet<Integer> hs = new HashSet<Integer>();
    23         
    24         //判断元素是否小于10
    25         while(hs.size()<10) {
    26            int num = r.nextInt(20)+1;
    27            hs.add(num);
    28         }
    29         
    30         Object[] obj = hs.toArray();
    31         Arrays.sort(obj);
    32         
    33         //遍历集合
    34         for(Object i : obj) {
    35             System.out.println(i);
    36         }
    37     }
    38 }

        B: 键盘录入学生按照总分从搞到底输出(TreeSet且用匿名内部类实现)

     1 package TreeSet_Scanner;
     2 
     3 import java.util.Comparator;
     4 import java.util.Scanner;
     5 import java.util.TreeSet;
     6 
     7 
     8 /** 
     9 * @author WYH
    10 * @version 2019年11月17日 下午3:25:25
    11 * 
    12 * 键盘录入5个学生信息,并且按照总分高低排序
    13 */
    14 public class TreeSetDemo {
    15     public static void main(String[] args) {
    16         //创建控制台输入对象
    17         Scanner sc = new Scanner(System.in);
    18         
    19         TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>(){
    20             @Override
    21             public int compare(Student s1, Student s2) {
    22                 /*int num = s1.getName().length() - s2.getName().length();
    23                 int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
    24                 int num3 = num2 == 0 ? s1.getSum() - s2.getSum() : num2;
    25                 return num3;*/
    26                 int num = s2.getSum() - s1.getSum();
    27                 int num2 = num == 0 ? s1.getMathNum() - s2.getMathNum() : num;
    28                 int num3 = num2 == 0 ? s1.getChinaNum() - s2.getChinaNum() : num2;
    29                 int num4 = num3 == 0 ? s1.getEngnishNum() - s2.getEngnishNum() : num3;
    30                 int num5 = num4 == 0 ? s1.getName().compareTo(s2.getName()) : num4;
    31                 return num5;
    32             }
    33         });
    34         
    35         
    36         System.err.println("录入开始:");
    37         for(int i = 0 ; i < 5 ; i++) {
    38             Student s = new Student();
    39             System.out.print("请输入第"+(i+1)+"个学生的姓名:");
    40             String name = sc.next();
    41             s.setName(name);
    42             System.out.print("请输入该学生的数学成绩:");
    43             int mNum = sc.nextInt();
    44             s.setMathNum(mNum);
    45             System.out.print("请输入该学生的语文成绩:");
    46             int cNum = sc.nextInt();
    47             s.setChinaNum(cNum);
    48             System.out.print("请输入该学生的英语成绩:");
    49             int eNum = sc.nextInt();
    50             s.setEngnishNum(eNum);
    51             
    52             int sum = mNum + cNum + eNum;
    53             s.setSum(sum);
    54             
    55             ts.add(s);
    56             System.out.println();
    57         }
    58         System.err.println("录入结束!");
    59         
    60         System.out.println("姓名	数学成绩	语文成绩	英语成绩	总分");
    61         for(Student s : ts) {
    62             System.out.println(s.getName()+"	"+s.getMathNum()+"	"+s.getChinaNum()+"	"+s.getEngnishNum()
    63             +"	"+s.getSum());
    64         }
    65         
    66         
    67     }
    68 
    69 }

    2、Collection 集合体系 总结:

    我们学完了Set集合,这个Collection体系下的另一个大模块,我们再来总结一下,把漏的LinkedList也总结一下:

      Collection

        | - - List 有序,可重复

          | - - ArrayList

              底层数据结构是数组,查询快,增删慢。

              线程不安全,效率高。

          | - - Vector

              底层数据结构是数组,查询快,增删慢。

              线程安全,效率低。

          | - - LinkedList

              底层数据结构是链表,查询慢,增删快。

              线程不安全,效率高。

        | - - Set 无序,唯一

          | - - HashSet

              底层数据结构是哈希表。

              如何保证元素唯一性的呢?

                依赖两个方法:hashCode()和equals()方法

                开发中自动生成这两个方法即可。

              | - - LinkedHashSet

                底层数据结构是链表和哈希表

                由链表保证元素有序

                由哈希表保证元素唯一

    人的类:重写方法

     1 package com.wyh.linkedHashSet;
     2 
     3 /** 
     4 * @author WYH
     5 * @version 2019年11月17日 上午9:21:02
     6 */
     7 public class Person {
     8     private String name;
     9     private int age;
    10     
    11     public Person(String name, int age) {
    12         super();
    13         this.name = name;
    14         this.age = age;
    15     }
    16     public Person() {
    17         super();
    18         // TODO Auto-generated constructor stub
    19     }
    20     
    21     public String getName() {
    22         return name;
    23     }
    24     public void setName(String name) {
    25         this.name = name;
    26     }
    27     public int getAge() {
    28         return age;
    29     }
    30     public void setAge(int age) {
    31         this.age = age;
    32     }
    33     
    34     //重写hashCode方法和equals方法
    35     @Override
    36     public int hashCode() {
    37         final int prime = 31;
    38         int result = 1;
    39         result = prime * result + age;
    40         result = prime * result + ((name == null) ? 0 : name.hashCode());
    41         return result;
    42     }
    43     @Override
    44     public boolean equals(Object obj) {
    45         if (this == obj)
    46             return true;
    47         if (obj == null)
    48             return false;
    49         if (getClass() != obj.getClass())
    50             return false;
    51         Person other = (Person) obj;
    52         if (age != other.age)
    53             return false;
    54         if (name == null) {
    55             if (other.name != null)
    56                 return false;
    57         } else if (!name.equals(other.name))
    58             return false;
    59         return true;
    60     }
    61     
    62 
    63 }

    测试类:

     1 package com.wyh.linkedHashSet;
     2 
     3 import java.util.LinkedHashSet;
     4 
     5 /** 
     6 * @author WYH
     7 * @version 2019年11月17日 上午9:40:25
     8 * 
     9 * LinkedHashSet: 底层是由哈希表和链表实现的
    10 * 
    11 * 哈希表确保元素的唯一性
    12 * 链表确保元素有序(存储和取出一致 )
    13 */
    14 public class LinkedHashSetDemo1 {
    15     public static void main(String[] args) {
    16         LinkedHashSet<Person> lhs = new LinkedHashSet<Person>();
    17         //创建Person类
    18         Person p1 = new Person("小虎",22);
    19         Person p2 = new Person("小强",23);
    20         Person p3 = new Person("小虎",22);
    21         Person p4 = new Person("小美",21);
    22         Person p5 = new Person("小雪",21);
    23         
    24         lhs.add(p1);
    25         lhs.add(p2);
    26         lhs.add(p3);
    27         lhs.add(p4);
    28         lhs.add(p5);
    29         
    30         //
    31         for(Person p : lhs) {
    32             System.out.println(p.getName()+"---"+p.getAge());
    33         }
    34         
    35     }
    36 
    37 }

          | - - TreeSet

              底层数据结构是红黑树。

              如何保证元素的排序的呢?

                自然排序

                比较器排序

              如何保证元素唯一性呢?

                根据比较的返回值是否是0来决定

    3、针对Collection集合我们到底使用谁呢?

        唯一吗?

          是:Set

            排序吗?

              是:TreeSet

              否:HashSet

          如果知道是Set,但是不知道是哪个Set,就用HashSet。

          否:List

            要安全吗?

              是:vector

              否:ArrayList 或者 LinkedList

                查询多:ArrayList

                增删多:LinkedList

          如果知道是List,但是不知道是哪个List,就用ArrayList。

        如果知道使用Collection集合,但是不知道使用谁,就用ArrayList。

      如果知道是用集合,就用ArrayList.

    4、在集合中常见的数据结构

      ArrayXxx:底层数据结构是数组,查询快,增删慢。 

      LinkedXxx: 底层数据结构是链表,查询慢,增删快。

      HashXxx: 底层数据结构是哈希表,依赖两个方法:hashCode() 和equals()方法

      TreeXxx: 底层数据结构是二叉树,两种方式排序,自然排序和比较器排序。

  • 相关阅读:
    poj 1013 Counterfeit Dollar
    poj百练2973:Skew数 进制问题
    poj百练2972 进制问题
    poj2080 Calendar
    POJ 1928 The Peanuts
    EXCEL打开CSV文件乱码的解决方法
    希望博客园做个软件职业生存状态调查问卷
    Linq使用Group By [转]
    ADO.NET 从DataTable中获取某列含有的不同值的几种方式
    本该遭拒的十大科技专利:苹果滑动解锁上榜[转]
  • 原文地址:https://www.cnblogs.com/wyh-study/p/11879023.html
Copyright © 2020-2023  润新知