Set集合

目录

HashSet

HashSet的特点

HashSet存储自定义对象并保证元素的唯一性

LinkedHashSet

数据结构

案例

TreeSet

特点

TreeSet集合自然排序

TreeSet集合比较器排序

TreeSet集合保证元素唯一和自然排序的原理

案例

产生10个不重复的1-20之间的随机整数

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

Set集合是一个不包含重复元素的collection,更确切地讲,set 不包含满足 e1.equals(e2) 的元素对 e1 和 e2 ,并且最多包含一个 null 元素。

HashSet

HashSet的特点

1)底层数据结构是哈希表。Hash线程不安全,集合元素可以是 null 。

哈希表是一个元素为链表的数组,综合了数组和链表的优点。

2)当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,然后根据 hashCode 值决定该对象在 HashSet 中的存储位置。

3)HashSet 集合判断两个元素相等的标准:两个对象通过 hashCode() 方法比较相等,并且两个对象的 equals() 方法返回值也相等。

4)HashSet 保证元素唯一性是靠元素重写 hashCode() 和 equals() 方法来保证的,如果不重写则无法保证。

HashSet存储自定义对象并保证元素的唯一性

定义的Student类

 import java.util.Objects;
 ​
 public class Student {
     private String name;
     private int age;
 ​
     public Student(String name, int age) {
         this.name = name;
         this.age = age;
     }
 ​
     @Override
     public String toString() {
         return "\""+this.name+
                 "\""+","+this.age ;
     }
 ​
     @Override
     public boolean equals(Object o) {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
         Student student = (Student) o;
         return age == student.age &&
                 Objects.equals(name, student.name);
     }
 ​
     @Override
     public int hashCode() {
         return Objects.hash(name, age);
     }
 }

测试类

 import java.util.HashSet;
 ​
 public class Test {
     public static void main(String[] args) {
         HashSet<Student> hashSet = new HashSet<>();
         hashSet.add(new Student("Alice", 18));
         hashSet.add(new Student("Jack", 17));
         hashSet.add(new Student("Jack", 18));
         hashSet.add(new Student("Helen", 19));
         hashSet.add(new Student("David", 22));
 ​
         System.out.println(hashSet);
     }
 }

LinkedHashSet

数据结构

链表和哈希表。链表保证元素的有序(和输入的顺序保持一致),哈希表保证元素的唯一。

所以 LinkedHashSet 的特点有:元素有序且唯一。

案例

实现 {21, 54, 23, 54, 21, 8, 2, 8, 23, 65} 存入 LinkedHashSet 集合,然后遍历集合验证元素是否有序且唯一。

 import java.util.LinkedHashSet;
 ​
 public class Test2 {
     public static void main(String[] args) {
         //{21, 54, 23, 54, 21, 8, 2, 8, 23, 65}
         LinkedHashSet<Integer> linkedHashSet = new LinkedHashSet<>();
         linkedHashSet.add(21);
         linkedHashSet.add(54);
         linkedHashSet.add(23);
         linkedHashSet.add(54);
         linkedHashSet.add(21);
         linkedHashSet.add(8);
         linkedHashSet.add(2);
         linkedHashSet.add(8);
         linkedHashSet.add(23);
         linkedHashSet.add(65);
         for (Integer i : linkedHashSet) {
             System.out.print(i+"\t");
         }
     }
 }

TreeSet

特点

元素唯一,并且可以对元素进行排序(自然排序,比较器排序)。

元素唯一性的保证是依靠compareTo()方法的返回值来确定的,如果返回0,则表示这两个元素相等,则不重复存储。

TreeSet集合自然排序

TreeSet集合中使用的是何种遍历方法,依据的是构造方法,如果是空参构造,那么就是自然排序;如果是有参构造,就是比较器排序。

使用TreeSet集合进行元素的自然排序,那么对元素有要求,要求这个元素必须实现Comparable接口 否则无法进行自然排序。

在Java API文档中我们会发现,常用的数据结构类,例如 Integer , String 等都实现了 Comparable 接口,所以在存储这些基本类型的对象时,不需要再考虑 Comparable 接口的问题。

例如在TreeSet集合中存入Integer类型的数据,然后遍历

 import java.util.TreeSet;
 ​
 public class Test {
     public static void main(String[] args) {
         TreeSet<Integer> treeSet = new TreeSet<>();
         treeSet.add(20);
         treeSet.add(18);
         treeSet.add(23);
         treeSet.add(22);
         treeSet.add(17);
         treeSet.add(24);
         treeSet.add(19);
         treeSet.add(18);
         treeSet.add(24);
 ​
         System.out.println(treeSet);
     }
 }

TreeSet集合比较器排序

设计Student类,实现Comparable接口并实现compareTo()方法

 public class Student implements Comparable<Student> {
     private String name;
     private int age;
 ​
     public Student() {
     }
 ​
     public Student(String name, int age) {
         this.name = name;
         this.age = age;
     }
 ​
     public String getName() {
         return name;
     }
 ​
     public void setName(String name) {
         this.name = name;
     }
 ​
     public int getAge() {
         return age;
     }
 ​
     public void setAge(int age) {
         this.age = age;
     }
 ​
     @Override
     public String toString() {
         return "Student{" +
                 "name='" + name + '\'' +
                 ", age=" + age +
                 '}';
     }
 ​
     @Override
     public int compareTo(Student student) {
         //按照姓名长度来排序
         int num = this.name.length() - student.name.length();
         //如果姓名长度一样,不能说明就是同一个对象,还得比较一下姓名的内容
         int num2 = num == 0 ? this.name.compareTo(student.name) : num;
         //如果姓名长度和内容一样,还得比较一下年龄是否一样
         return num2 == 0 ? this.age - student.age : num2;
         //根据返回值的 正 负 0 来决定元素在二叉树中放置的左右位置,0 就是不往里面放。
     }
 }

测试类中创建TreeSet集合,并存入Student对象

 import java.util.TreeSet;
 ​
 public class MyTest3 {
     public static void main(String[] args) {
         //比较器排序:
         TreeSet<Student> treeSet = new TreeSet<>();
         //存储学生对象,并且根据学生的姓名的长度进行排序
         treeSet.add(new Student("张三", 23));
         treeSet.add(new Student("李四", 23));
         treeSet.add(new Student("李四", 24));
         treeSet.add(new Student("刘洋asdfasf", 23));
         treeSet.add(new Student("李四asfasfasdf", 10));
         treeSet.add(new Student("王五dd", 60));
         treeSet.add(new Student("张三ddfdfd", 23));
         treeSet.add(new Student("赵六dfdfd", 19));
         treeSet.add(new Student("田七dfdf", 28));
         //增强for循环遍历集合
         for (Student student : treeSet) {
             System.out.println(student);
         }
     }
 }

TreeSet集合保证元素唯一和自然排序的原理

TreeSet存储元素时采用的方法是二叉树存储,第一个放入的元素是根,后来的元素和根比较,小的放左边,大的放右边,相同的不存储。取的时候按照左中右的顺序,刚好实现了有序的特性。

例如,将 20, 18, 23, 22, 17, 24, 19, 18, 24 存入TreeSet集合中,

案例

产生10个不重复的1-20之间的随机整数

思路:

1)要产生随机数,可以使用 Math 工具类的random()方法来产生随机数,然后只需要对产生的随机数进行处理即可达到1-20之间的要求。

2)要使产生的随机数不能重复,可以将产生的随机数放在HashSet或者TreeSet集合中,推荐使用TreeSet集合,因为即保证了元素唯一性,又可以进行自然排序,输出时对结果一目了然。

3)因为生成的随机数可能重复,所以选择使用while循环或者递归来完成。

 import java.util.TreeSet;
 ​
 public class Test2 {
     public static void main(String[] args) {
         //创建TreeSet集合
         TreeSet<Integer> treeSet = new TreeSet<>();
 ​
         while (treeSet.size() < 10) {
             //生成1-100随机整数
             int ele = (int) (Math.random() * 100) + 1;
             if (ele > 0 && ele <= 20) {
                 treeSet.add(ele);
             }
         }
         //增强for遍历集合
         for (Integer integer : treeSet) {
             System.out.print(integer+"\t");
         }
     }
 }

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

思路:

1)首先要自定义Student类,成员变量要有 姓名name, 语文成绩chineseScore, 数学成绩mathScore, 英语成绩englishScore ,需要使用总分进行排序,那么可以定义一个 总分totalScore 方便排序时进行比较。

2)创建TreeSet集合,因为TreeSet集合的元素唯一且有序,简化了去重的一个步骤;而有序,我们需要设计比较器来完成。

3)创建扫描器对象,将数据输入存储进集合,遍历集合。

Student类:

 public class Student {
     private String name;
     private int chineseScore;
     private int mathScore;
     private int englishScore;
 ​
     public Student(String name, int chineseScore, int mathScore, int englishScore) {
         this.name = name;
         this.chineseScore = chineseScore;
         this.mathScore = mathScore;
         this.englishScore = englishScore;
     }
 ​
     public int getTotalScore() {
         return this.chineseScore
                 +this.englishScore
                 +this.mathScore;
     }
 ​
     public String getName() {
         return name;
     }
 ​
     public int getChineseScore() {
         return chineseScore;
     }
 ​
     public int getMathScore() {
         return mathScore;
     }
 ​
     public int getEnglishScore() {
         return englishScore;
     }
 ​
     @Override
     public String toString() {
         return "Student{" +
                 "name='" + name + '\'' +
                 ", chineseScore=" + chineseScore +
                 ", mathScore=" + mathScore +
                 ", englishScore=" + englishScore +
                 ", totalScore=" + getTotalScore()+
                 '}';
     }
 }

测试类:

 import java.util.Comparator;
 import java.util.Scanner;
 import java.util.TreeSet;
 ​
 public class Test3 {
     public static void main(String[] args) {
         //创建集合并传入比较器
         TreeSet<Student> treeSet = new TreeSet<>(new Comparator<Student>() {
             @Override
             public int compare(Student s1, Student s2) {
                 return -(s1.getTotalScore()-s2.getTotalScore());
             }
         });
         Scanner sc = new Scanner(System.in);
         //键盘录入元素,这里以3个元素为例
         for (int i = 1; i <= 3; i++) {
             treeSet.add(new Student(sc.next(),sc.nextInt(),sc.nextInt(),sc.nextInt()));
         }
         //增强for遍历集合
         for (Student student : treeSet) {
             System.out.println(student);
         }
     }
 }

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值