2020.5.17

Set接口

  1. 特点:相对于list接口,set接口不能包含重复元素,并且可以有null元素
  2. 常用的set子集合

HashSet集合

  1. 特点:底层用的是哈希表存放元素,在1.7之前哈希表是用链表和数组存放,1.8之后优化成链表,数组和二叉树。

  2. 哈希表原理:

  • 一个数据储存过程,先根据元素通过hash函数,计算出元素的哈希值,由于哈希值比较大,然后用该数字对数组长度取余,得到的数据就是数组对应的下标,由于数组长度是有限的,所以在存储过程中可能会出现碰撞,多个元素计算的结果对应一个数组下标,链表就解决了这个情况,如果计算出的数组下标相同,就判断是否是同一个元素,如果是同一个元素,就不存储。不是就使用链表存放。

  • 因此我们在存放对象时,对象就要重写Hash()方法那和equals()方法,重写Hash()方法是为了减少碰撞,重写equals()是避免元素重复。

    • 元素特征转变为数组下标的方法就是散列法。散列法当然不止一种,下面列出三种比较常用的:

    1,除法散列法
    最直观的一种,上图使用的就是这种散列法,公式:
    index = value % 16
    学过汇编的都知道,求模数其实是通过一个除法运算得到的,所以叫“除法散列法”。

    2,平方散列法
    求index是非常频繁的操作,而乘法的运算要比除法来得省时(对现在的CPU来说,估计我们感觉不出来),所以我们考虑把除法换成乘法和一个位移操作。公式:
    index = (value * value) >> 28 (右移,除以2^28。记法:左移变大,是乘。右移变小,是除。)
    如果数值分配比较均匀的话这种方法能得到不错的结果,但我上面画的那个图的各个元素的值算出来的index都是0——非常失败。也许你还有个问题,value如果很大,value * value不会溢出吗?答案是会的,但我们这个乘法不关心溢出,因为我们根本不是为了获取相乘结果,而是为了获取index。

    3,斐波那契(Fibonacci)散列法

    平方散列法的缺点是显而易见的,所以我们能不能找出一个理想的乘数,而不是拿value本身当作乘数呢?答案是肯定的。

    1,对于16位整数而言,这个乘数是40503
    2,对于32位整数而言,这个乘数是2654435769
    3,对于64位整数而言,这个乘数是11400714819323198485

      这几个“理想乘数”是如何得出来的呢?这跟一个法则有关,叫黄金分割法则,而描述黄金分割法则的最经典表达式无疑就是著名的斐波那契数列,即如此形式的序列:0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377, 610, 987, 1597, 2584, 4181, 6765, 10946,…。另外,斐波那契数列的值和太阳系八大行星的轨道半径的比例出奇吻合。对我们常见的32位整数而言,公式: index = (value * 2654435769) >> 28
    

    原文链接:https://blog.csdn.net/duan19920101/article/details/51579136

  • 影响Hash碰撞(冲突)发生的除了Hash函数本身意外,底层数组容量也是一个重要原因。很明显,极端情况下如果数组容量为1,哪必然发生碰撞,如果数组容量无限大,哪碰撞的概率非常之低。所以,哈希碰撞还取决于负载因子。负载因子是存储的键值对数目与数组容量的比值,比如数组容量100,当前存贮了90个键值对,负载因子为0.9。负载因子决定了哈希表什么时候扩容,如果负载因子的值太大,说明存储的键值对接近容量,增加碰撞的风险,如果值太小,则浪费空间。

  • 优点:因为它集合了数组和链表的特点,所以它查询块,增删也快。

  • 缺点:它是基于数组的,数组创建后难于扩展,某些哈希表被基本填满时,性能下降得非常严重,所以必须要清楚表中将要存储多少数据。

  1. 构造方法及方法

  2. 代码示例:

1.package org.westos.demo0518; /*Author:LH
CreatTime:2020.05.18.15:04*/import java.util.HashSet;
import java.util.Iterator;
import java.util.function.Consumer;public class MyTest {public static void main(String[] args) {HashSet<Integer> hashset = new HashSet<>();hashset.add(100);hashset.add(200);hashset.add(200);hashset.add(300);System.out.println(hashset);System.out.println("========");
//        迭代器遍历方法Iterator<Integer> iterator = hashset.iterator();while (iterator.hasNext()) {System.out.println(iterator.next());}System.out.println("++++++++");
//        增强for循环遍历方法for (Integer integer : hashset) {System.out.println(integer);}System.out.println("++++++++");
//        foreach遍历方法hashset.forEach(new Consumer<Integer>() {@Overridepublic void accept(Integer integer) {System.out.println(integer);}});/*集合中存放的是Integer和String类型时,不用手动重写hash方法和equals方法* 因为这两个类型已经默认重写了此方法,所以数据才会存进去并去重。* */}
}
2.package org.westos.demo0518; /*Author:LH
CreatTime:2020.05.18.15:15*/
import java.util.HashSet;
//要将Student对象存入set集合,对象就要重写Hash方法和equals方法,来保证元素唯一性
public class MyTest2 {public static void main(String[] args) {HashSet<Student> hashset = new HashSet<>();hashset.add(new Student("小王",23));hashset.add(new Student("李辉",23));hashset.add(new Student("王培红",24));hashset.add(new Student("扎西格勒",25));hashset.add(new Student("东方日出2",26));
//        System.out.println(hashset);for (Student student : hashset) {System.out.println(student.toString());}}
}
package org.westos.demo0518; /*Author:LH
CreatTime:2020.05.18.15:16*/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;}public Student() {}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;}@Overridepublic 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);}@Overridepublic int hashCode() {return Objects.hash(name, age);}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}
3.package org.westos.demo0518; /*Author:LH
CreatTime:2020.05.18.15:51*/import java.util.ArrayList;
import java.util.LinkedHashSet;//将list集合中重复元素去除。
//可以自己写方法去掉,也可以根据set集合的特点,转换
public class MyTest3 {public static void main(String[] args) {ArrayList<Integer> list = new ArrayList<>();list.add(100);list.add(100);list.add(300);list.add(200);list.add(300);list.add(500);list.add(600);list.add(700);for (Integer integer : list) {System.out.println(integer);}System.out.println("==========");
//        使用有参构造,将list集合传入,创建新的set集合,将自动去除重复元素LinkedHashSet<Object> linkedHashSet = new LinkedHashSet<>(list);for (Object o : linkedHashSet) {System.out.println(o);}}
}

LinkedHashSet集合

  1. 它的底层数据结构是链表和哈希表,链表保证有序(存取顺序一致),哈希表保证元素唯一。因此此集合的特点是元素有序,且唯一。但是线程不安全。
  2. 构造方法及方法

  1. 案例演示:
1.package org.westos.demo0518.LinkedHashSet; /*Author:LH
CreatTime:2020.05.18.16:08*/import java.util.LinkedHashSet;
//LinkedHashSet集合存取元素顺序一致,保证元素唯一性。
public class Test {public static void main(String[] args) {LinkedHashSet<Integer> integers = new LinkedHashSet<>();integers.add(100);integers.add(200);integers.add(200);integers.add(300);integers.add(300);integers.add(400);for (Integer integer : integers) {System.out.println(integer);}}
}2.package org.westos.demo0518.LinkedHashSet; /*Author:LH
CreatTime:2020.05.18.16:35*/import java.util.LinkedHashSet;
//LinkedHashSet存自定义对象,也要重写Hash方法和equals方法,来保证元素的唯一性
public class Test2 {public static void main(String[] args) {LinkedHashSet<Student> linkedHashSet = new LinkedHashSet<>();linkedHashSet.add(new Student("李瑶",23));linkedHashSet.add(new Student("李其",23));linkedHashSet.add(new Student("李其",23));linkedHashSet.add(new Student("章子路",23));linkedHashSet.add(new Student("章子路",23));linkedHashSet.add(new Student("上官风雨",23));for (Student student : linkedHashSet) {System.out.println(student.toString());}}
}
package org.westos.demo0518.LinkedHashSet;/*Author:LH
CreatTime:2020.05.18.15:16*/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;}public Student() {}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;}@Overridepublic 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);}@Overridepublic int hashCode() {return Objects.hash(name, age);}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}

TreeSet集合

  1. 底层数据结构是二叉树,可以对元素排序,并且保证元素唯一性。
  2. 二叉树原理图

  • 二叉树存放数据,将进来的数据和根数据对比,根据排序方法,将数据放在其左右,相同元素不能被存放。
  1. 方法和构造方法

代码演示:

1.package org.westos.demo0518.TreeSet; /*Author:LH
CreatTime:2020.05.19.16:26*/
//TreeSet集合使用自然排序存Integer类型数据
import java.util.Iterator;
import java.util.TreeSet;
import java.util.function.Consumer;public class Test {public static void main(String[] args) {TreeSet<Integer> treeSet = new TreeSet<>();treeSet.add(23);treeSet.add(14);treeSet.add(15);treeSet.add(28);treeSet.add(8);Iterator<Integer> iterator = treeSet.iterator();while (iterator.hasNext()) {System.out.println(iterator.next());}for (Integer integer : treeSet) {System.out.println(integer);}treeSet.forEach(new Consumer<Integer>() {@Overridepublic void accept(Integer integer) {System.out.println(integer);}});}
}
2.package org.westos.demo0518.TreeSet; /*Author:LH
CreatTime:2020.05.19.16:31*/import java.util.Comparator;
import java.util.TreeSet;
//使用比较器排序
public class Test2 {public static void main(String[] args) {//        重写Comparator接口的compare方法。TreeSet<Integer> treeSet = new TreeSet<>(new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o1-o2;}});treeSet.add(12);treeSet.add(34);treeSet.add(14);treeSet.add(67);treeSet.add(2);for (Integer integer : treeSet) {System.out.println(integer);}}
}
3.package org.westos.demo0518.TreeSet; /*Author:LH
CreatTime:2020.05.19.16:35*/import java.util.TreeSet;
//TreeSet集合使用自然排序存自定义对象
public class TestStudent {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("张三",25));treeSet.add(new Student("王五",28));treeSet.add(new Student("赵六",23));for (Student student : treeSet) {System.out.println(student.toString());}}
}
package org.westos.demo0518.TreeSet;/*Author:LH
CreatTime:2020.05.18.15:16*/
// 自定义对象实现 Comparable<Student>,如果能明确泛型,一定要准确的把泛型写出来,此处不写也不会报错,
//只是重写compareTo(Student o)方法时,括号给的是Object数据类型,需要转型。
public class Student implements Comparable<Student> {private String name;private int age;public Student(String name, int age) {this.name = name;this.age = age;}public Student() {}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;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}@Override
//    根据年龄大小排序,如果年龄相同,再判断姓名是否相同,相同就是同一个元素,不同则存进来public int compareTo(Student o) {int num=this.age-o.age;int num2=num==0?this.name.compareTo(o.name):num;return num2;}
}
4.package org.westos.demo0518.TreeSet; /*Author:LH
CreatTime:2020.05.19.17:09*/import java.util.Comparator;
import java.util.TreeSet;
//使用比较器对自定义对象排序
public class TestStudent2 {public static void main(String[] args) {TreeSet<Student2> treeSet = new TreeSet<>(new Comparator<Student2>() {@Override//    根据年龄大小排序,如果年龄相同,再判断姓名是否相同,相同就是同一个元素,不同则存进来public int compare(Student2 o1, Student2 o2) {int num=o1.getAge()-o2.getAge();int num2=num==0?o1.getName().compareTo(o2.getName()):num;return num2;}});treeSet.add(new Student2("张三",18));treeSet.add(new Student2("李四",18));treeSet.add(new Student2("王五",27));treeSet.add(new Student2("李辉",18));treeSet.add(new Student2("张三",18));for (Student2 student2 : treeSet) {System.out.println(student2.toString());}}
}
package org.westos.demo0518.TreeSet;/*Author:LH
CreatTime:2020.05.18.15:16*/public class Student2 {private String name;private int age;public Student2(String name, int age) {this.name = name;this.age = age;}public Student2() {}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;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}
5.package org.westos.demo0518.TreeSet;import java.util.LinkedHashSet;
import java.util.Random;/*Author:LH
CreatTime:2020.05.19.17:17*/
/*编写一个程序,获取10个1至20的随机数,要求随机数不能重复。并把最终的随机数输出到控制台。*/
public class Test3 {public static void main(String[] args) {Random random = new Random();LinkedHashSet<Integer> integers = new LinkedHashSet<>();while (integers.size()<=10) {int i = random.nextInt(20)+1;integers.add(i);}for (Integer integer : integers) {System.out.println(integer);}}
}
6.package org.westos.demo0518.TreeSet; /*Author:LH
CreatTime:2020.05.19.17:51*///案例演示: 需求:键盘录入3个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台。import java.util.Comparator;
import java.util.TreeSet;/*** 步骤:*      a: 自定义一个学生类*        b: 创建一个TreeSet集合对象(使用比较器进行排序)*      c: 键盘录入学生的数据,然后把学生的数据封装成一个学生对象,把学生对象添加到集合中*         d: 遍历集合*/
public class Test4 {public static void main(String[] args) {TreeSet<Student3> treeSet = new TreeSet<>(new Comparator<Student3>() {@Overridepublic int compare(Student3 o1, Student3 o2) {int num=o1.getSum()-o2.getSum();int num2=num==0?o1.getName().compareTo(o2.getName()):num;return num2;}});treeSet.add(new Student3("张三",60,20,40));treeSet.add(new Student3("张三",67,20,47));treeSet.add(new Student3("李四",60,20,40));treeSet.add(new Student3("王五",69,90,41));treeSet.add(new Student3("张三",67,20,47));treeSet.add(new Student3("赵六",27,20,47));for (Student3 student3 : treeSet) {System.out.println(student3.toString());}}
}
package org.westos.demo0518.TreeSet; /*Author:LH
CreatTime:2020.05.19.17:53*/public class Student3 {private String name;private  int chineseScore;private  int englishScore;private  int mathScore;public Student3(String name, int chineseScore, int englishScore, int mathScore) {this.name = name;this.chineseScore = chineseScore;this.englishScore = englishScore;this.mathScore = mathScore;}public Student3() {}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getChineseScore() {return chineseScore;}public void setChineseScore(int chineseScore) {this.chineseScore = chineseScore;}public int getEnglishScore() {return englishScore;}public void setEnglishScore(int englishScore) {this.englishScore = englishScore;}public int getMathScore() {return mathScore;}public void setMathScore(int mathScore) {this.mathScore = mathScore;}public int getSum(){return chineseScore+englishScore+mathScore;}@Overridepublic String toString() {return"name='" + name + '\''+'\t'+"chineseScore=" + chineseScore +'\t'+ "englishScore=" + englishScore +'\t'+"mathScore=" + mathScore +'\t'+"总分"+getSum();}
}public void setEnglishScore(int englishScore) {this.englishScore = englishScore;}public int getMathScore() {return mathScore;}public void setMathScore(int mathScore) {this.mathScore = mathScore;}public int getSum(){return chineseScore+englishScore+mathScore;}@Overridepublic String toString() {return"name='" + name + '\''+'\t'+"chineseScore=" + chineseScore +'\t'+ "englishScore=" + englishScore +'\t'+"mathScore=" + mathScore +'\t'+"总分"+getSum();}
}

Set接口以及子集合(HashSet/LinkedHashSet/TreeSet)的用法和数据结构相关推荐

  1. 集合之Collection家族的 List接口+LinkedList+Vector+Stack及Set接口+HashSet+LinkedHashSet+TreeSet

    集合之Collection家族的 List接口+LinkedList+Vector+Stack及Set接口+HashSet+LinkedHashSet+TreeSet 一.LinkedList 1.L ...

  2. 集合{LinkedHashMap TreeMap HashSet LinkedHashSet TreeSet 快速失败机制 ConcurrentHashMap CAS 多线程协同扩容}(二)

    目录标题 LinkedHashMap Map集合框架结构体系图 什么是LinkedHashMap Linked 链式 的意思 HashMap "哈希映射"的意思 LinkedHas ...

  3. Java—Set集合详解(HashSet/LinkedHashSet/TreeSet/EnumSet)

    关注微信公众号:CodingTechWork,一起学习进步. Set集合介绍 Set集合的概念   Set集合类似于一个容器,程序把很多对象保存到Set集合中,Set集合对添加顺序不记录,当有重复的对 ...

  4. JavaSE Set HashSet LinkedHashSet TreeSet 集合练习

    day17目录: SetHashSetLinkedHashSetTreeSet 集合练习 17.08_集合框架(Set集合概述及特点)(掌握) A:Set集合概述及特点: 通过API查看即可 B: 案 ...

  5. Java集合框架:Set(HashSet,LinkedHashSet,TreeSet)

    欢迎支持笔者新作:<深入理解Kafka:核心设计与实践原理>和<RabbitMQ实战指南>,同时欢迎关注笔者的微信公众号:朱小厮的博客. 欢迎跳转到本文的原文链接:https: ...

  6. HashSet、TreeSet和LinkedHashSet

    Set不能包含重复的元素.有三个通用的set接口的实现:HashSet.TreeSet和LinkedHashSet.什么时候用以及用哪个是一个重要的问题.总体来说,如果要一个快速的集合,就用HashS ...

  7. Set 、HashSet、TreeSet、LinkedHashSet、EnumSet

    Set 底层原理: java中set及其子类都是由对应的Map实现的,如HashSet由HashMap实现,TreeSet由TreeMap实现等等. private static final Obje ...

  8. HashSet 与TreeSet和LinkedHashSet的区别

    今天项目开发,需要通过两个条件去查询数据库数据,同时只要满足一个条件就可以取出这个对象.所以通过取出的数据肯定会有重复,所以要去掉重复项. 如果用list集合接收两次的返回对象,那么肯定是有重复对象在 ...

  9. HashSet vs TreeSet vs LinkedHashSet

    使用Set集合的主要原因是因为Set集合里面没有重复的元素.Set集合有三个常见的实现类:HashSet,TreeSet,LinkedHashSet.什么时候,选择哪一个使用非常重要.简单的说,如果你 ...

  10. Java容器源码分析-HashSet vs TreeSet vs LinkedHashSet

    2019独角兽企业重金招聘Python工程师标准>>> 这几天看了下容器的源码,总结一下HashSet vs TreeSet vs LinkedHashSet的区别, 如下图,col ...

最新文章

  1. python list遍历
  2. volatile 关键字是如何保证可见性的?
  3. 给我的Nokia3100
  4. JavaScript_HTML DEMO_2_事件
  5. 13_展示商品的详情
  6. STM32串口通信基本原理
  7. 《大数据之路:阿里巴巴大数据实践》-第1篇 数据技术篇 -第3章数据同步
  8. Clion笔记- 菜单栏不见了...
  9. 利用E4A编写APP获取安卓手机加速度传感器数据
  10. html svg图片不显示,html/css svg怎么显示不出来?
  11. 天使的微笑——《天使爱美丽》
  12. python 正则 匹配任意字符串_python中正则匹配
  13. 【财务】FMS财务管理系统---应收管理
  14. LPCSTR,LPCTSTR,LPCWSTR的区别
  15. 二维图形的基本变换与裁剪的变换矩阵
  16. 毕业季!清北毕业生都去哪了?
  17. [分享]使用iphone让你的电脑PC或MAC上网- 苹果官网说法
  18. 项目管理需要一个在线团队协作平台
  19. 成功解决第nnnnnn次couldn't communicate with the NVIDIA driver后的方案总结
  20. 考HCIP是否只考背题就能考过?

热门文章

  1. android手机otg,OTG是什么?Android手机OTG功能怎么开启和使用?
  2. excel 去掉公式保留数值的方法
  3. 80psi等于多少kpa_1kpa等于多少psi
  4. Jenkins(03):配置Jenkins自动发送邮件
  5. 【项目二、蜂巢检测项目】二、模型改进:YOLOv5s-ShuffleNetV2
  6. 镜头MTF值的基本原理和解读
  7. vscode下载慢、安装、插件和使用(七七)
  8. 36氪专访| 友盟+CEO朋新宇:大数据赛道会越来越宽,同时也会越来越头部化
  9. 游戏策划笔记:记忆点的构造
  10. 中国智能POS终端行业市场供需与战略研究报告