当前位置: 首页 > news >正文

Java—— 集合 Set

Set集合的特点

无序:存取顺序不一致
不重复:可以去除重复
无索引:没有带索引的方法,所以不能使用普通for循环遍历,也不能通过索引来进行操作

Set集合的方法 

Set接口中的方法基本上与Collection的API一致。  

代码演示

import java.util.HashSet;
import java.util.Set;public class Test1 {public static void main(String[] args) {Set<String> s = new HashSet<>();//Set集合不能重复,添加重复元素时会添加错误,返回falseSystem.out.println(s.add("aaa"));//trueSystem.out.println(s.add("bbb"));//trueSystem.out.println(s.add("ccc"));//trueSystem.out.println(s.add("aaa"));//false//Set集合无序,存入和输出的顺序不一致System.out.println(s);//[aaa, ccc, bbb]}
}

Set集合的实现类的特点

HashSet:无序、不重复、无索引
LinkedHashSet:有序、不重复、无索引
TreeSet:可排序、不重复、无索引

引理

哈希表

哈希表是一种对于增删改查数据性能都较好的结构

组成:

JDK8之前:数组+链表
JDK8开始:数组+链表+红黑树

 哈希值

根据hashCode方法算出来的int类型的整数
该方法定义在Object类中,所有对象都可以调用,默认使用地址值进行计算
一般情况下,会重写hashCode方法,利用对象内部的属性值计算哈希值

自定义对象的哈希值特点

如果没有重写hashCode方法,不同对象计算出的哈希值是不同的
如果已经重写hashcode方法,不同的对象只要属性值相同,计算出的哈希值就是一样的

HashSet

HashSet底层原理

HashSet集合底层采取哈希表存储数据 

存入元素的底层步骤

1.创建一个默认长度16,默认加载因子0.75的数组,数组名table
2.根据需要存入元素的哈希值跟数组的长度计算出应存入的位置

        int index = (数组长度-1) & 哈希值;
3.判断当前位置是否为null,如果是null直接存入
4.如果位置不为null,表示有元素,则调用equals方法比较属性值
5.属性值一样:不存,属性值不一样:存入元素,形成链表
        JDK8以前:新元素存入数组,老元素挂在新元素下面
        JDK8以后:新元素直接挂在老元素下面

 

注意事项

1.加载因子0.75:当数组中的元素达到数组长度的0.75倍时,数组长度扩容为原先两倍

2.数组某位置形成了链表且还有元素要存入到该位置,需要比较链表上所有元素的属性值,只有都不相同才能存入成功

3.JDK8以后,当链表长度超过8,而且数组长度大于等于64时,自动转换为红黑树
4.如果集合中存储的是自定义对象,必须要重写hashCode和equals方法

底层原理解释HashSet的特点

无序:元素通过哈希值存入,但输出时是从数组0索引开始遍历输出,因此存取顺序不一致

不重复:通过hashCode和equals方法进行约束,元素属性值相同存入失败

无索引:底层采取哈希表存储数据,存在链表

案例练习

利用HashSet集合去除重复元素
需求:创建一个存储学生对象的集合,存储多个学生对象。
要求:学生对象的成员变量值相同,我们就认为是同一个对象,存入失败

Student类

import java.util.Objects;public class 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;}//重写equals,hashCode方法@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 + '\'' +", " + age +'}';}
}

实现类

import java.util.HashSet;public class Test2 {public static void main(String[] args) {HashSet s = new HashSet<>();Student s1 = new Student("zhangsan", 23);Student s2 = new Student("lisi", 24);Student s3 = new Student("wangwu", 25);Student s4 = new Student("zhangsan", 23);System.out.println(s.add(s1));//trueSystem.out.println(s.add(s2));//trueSystem.out.println(s.add(s3));//trueSystem.out.println(s.add(s4));//falseSystem.out.println(s);//[Student{wangwu', 25}, Student{lisi', 24}, Student{zhangsan', 23}]}
}

LinkedHashSet

LinkedHashSet底层原理

底层数据结构依然是哈希表,但每个元素又额外多了一个双链表的机制记录存储的顺序。 

底层原理解释LinkedHashSet的特点

有序:保证存取元素顺序一致,因为有双链表机制可以从头节点按存入的顺序一直到尾节点

TreeSet

TreeSet底层原理

TreeSet集合底层是基于红黑树的数据结构实现排序的,增删改查性能都较好。

所以在自定义对象的类中不用重写equals和hashCode方法

存入TreeSet集合的数据会进行排序

什么是红黑树

1.每一个节点或是红色的,或者是黑色的
2.根节点必须是黑色
3.如果一个节点没有子节点或者父节点,则该节点相应的指针属性值为Nil,这些Nil视为叶节点,每个叶节点(Nil)是黑色的
4.如果某一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点相连的情况)
5.对每一个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点

红黑树节点添加规则
图片来源于网络

TreeSet默认排序规则

String、Integer等类在代码底层已经实现了Comparable接口写好了排序规则

对于数值类型:Integer,Double,默认按照从小到大的顺序进行排序。
对于字符、字符串类型:按照字符在ASCII码表中的数字升序进行排序。

TreeSet自定义排序规则的两种方式

默认排序/自然排序

javabean类实现Comparable接口指定排序规则

自定义对象类在实现Comparable接口后要自定义排序规则

(String、Integer等类在代码底层已经写好了排序规则,也就是默认排序规则)

 案例演示

自定义Student类,按照学生年龄升序排序

Student类

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;}@Overridepublic String toString() {return "Student{" + name + '\'' +", " + age +'}';}//自定义排序规则@Overridepublic int compareTo(Student o) {return this.getAge() - o.getAge();}
}

测试类

import java.util.TreeSet;public class Test {public static void main(String[] args) {Student s1 = new Student("zhangsan", 23);Student s2 = new Student("lisi", 24);Student s3 = new Student("wangwu", 25);TreeSet<Student> ts = new TreeSet<>();ts.add(s3);ts.add(s2);ts.add(s1);for (Student s : ts) {System.out.println(s);}//Student{zhangsan', 23}//Student{lisi', 24}//Student{wangwu', 25}}
}

this:表示当前要添加的元素
o:表示已经在红黑树中存在的元素
返回值:
负数:认为要添加的元素是小的,存左边
正数:认为要添加的元素是大的,存右边
0:认为要添加的元素已经存在,舍弃 

比较器排序

创建TreeSet对象时候,传递比较器Comparator指定规则

案例演示

存入四个字符串,“c”,“ab”,“df”,“qwer”,按照长度排序,如果一样长则按照首字母排序

public class Test3 {public static void main(String[] args) {//存入四个字符串,“c”,“ab”,“df”,“qwer”//按照长度排序,如果一样长则按照首字母排序TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {int i = o1.length() - o2.length();i = i == 0 ? o1.compareTo(o2) : i;return i;}});ts.add("c");ts.add("ab");ts.add("df");ts.add("qwer");System.out.println(ts);//[c, ab, df, qwer]}
}

o1:表示当前要添加的元素

o2:表示已经在红黑数中存在的元素

返回值规则与默认排序/自然排序相同

注意事项 

使用原则:默认使用第一种,如果第一种不能满足当前需求,就使用第二种

如果两种方式都存在,以第二种指定的排序规则排序

各种单列集合的使用场景

1. 如果想要集合中的元素可重复
        用ArrayList集合,基于数组的。(用的最多)
2.如果想要集合中的元素可重复,而且当前的增删操作明显多于查询
        用LinkedList集合,基于链表的。
3.如果想对集合中的元素去重
        用HashSet集合,基于哈希表的。(用的最多)
4.如果想对集合中的元素去重,而且保证存取顺序
        用LinkedHashSet集合,基于哈希表和双链表,效率低于HashSet。
5.如果想对集合中的元素进行排序
        用TreeSet集合,基于红黑树。后续也可以用List集合实现排序。 

相关文章:

  • 【Spark】使用Spark集群搭建-Standalone
  • 在Web应用中集成Google AI NLP服务的完整指南:从Dialogflow配置到高并发优化
  • FFmpeg 项目中的三大核心工具详解
  • 企业管理软件:数字化转型的核心引擎
  • spdlog日志器(logger)的创建方法大全
  • 从0到1:Python机器学习实战全攻略(8/10)
  • 03.Golang 切片(slice)源码分析(二、append实现)
  • 循环语句:for、range -《Go语言实战指南》
  • 【layout组件 与 路由镶嵌】vue3 后台管理系统
  • uniapp(微信小程序)>关于父子组件的样式传递问题(自定义组件样式穿透)
  • 涨薪技术|0到1学会性能测试第58课-垃圾回收器
  • 【Pandas】pandas DataFrame cummax
  • 【LeeCode】1.两数之和
  • 读取.ini后缀类型的马达配置文件并进行赋值
  • 【操作系统】零拷贝技术
  • LearnOpenGL02:绘制三角形和矩形
  • 【办公类-99-06】20250512用Python制作PPT的GIF照片动图(统一图片大小、自定义不同切换秒数,以蝴蝶为例)
  • 家具制造行业的现状 质检LIMS如何赋能家具制造企业质检升级
  • 学习黑客5 分钟深入浅出理解系列之 Windows 资源监视器
  • LeetCode 热题 100_只出现一次的数字(96_136_简单_C++)(哈希表;哈希集合;排序+遍历;位运算)
  • 习近平出席中国-拉美和加勒比国家共同体论坛第四届部长级会议开幕式
  • 这一次,又被南昌“秀”到了
  • 澎湃思想周报|欧洲胜利日之思;教育监控与学生隐私权争议
  • 深一度|在亚马尔的天才面前,姆巴佩戴上“帽子”又如何
  • 四川资阳市原市长王善平被双开,“笃信风水,大搞迷信活动”
  • 全国人大常委会启动食品安全法执法检查