Set 集合详解:无序、不重复的集合!
开篇语
哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云/阿里云/华为云/51CTO;欢迎大家常来逛逛
今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。
我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀,加以复盘,查缺补漏。
小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!
前言
在 Java 中,Set
集合是一种非常常用的集合类型,它与 List
不同,最大的特点是无序且不重复。如果你需要存储一组不重复的数据,同时不关心元素的顺序,Set
就是一个理想的选择。在本文中,我们将详细分析 Set
集合的实现原理,讲解 HashSet
、LinkedHashSet
、TreeSet
的特点,以及它们在实际项目中的应用场景。
1. HashSet 实现原理
HashSet
是 Java 中最常用的 Set
集合实现类。它基于哈希表(HashMap
)实现,存储元素时依赖于元素的哈希值。下面我们来详细了解一下 HashSet
的实现原理。
1.1 HashSet 的基本特点
- 无序:
HashSet
不保证元素的顺序,因此存入集合的元素不一定按照插入顺序排列。 - 不重复:
HashSet
不允许存储重复元素。如果尝试加入一个重复元素,添加操作会被忽略。 - 线程不安全:
HashSet
是线程不安全的,如果多线程环境下使用它,需要外部进行同步控制。
1.2 HashSet 的底层原理
HashSet
通过 HashMap
来实现。具体来说,HashSet
的每个元素都被存储为 HashMap
的键,而 HashMap
的值是一个固定的常量对象。这使得 HashSet
能够通过哈希表来保证元素的快速查找,同时保证不重复。
- 在向
HashSet
中添加元素时,HashSet
会计算元素的哈希值,并将元素作为HashMap
的键添加到哈希表中。 - 如果插入的元素已经存在(即哈希值相同且
equals()
方法返回true
),则该元素不会被重复添加。
import java.util.HashSet;
public class HashSetExample {
public static void main(String[] args) {
HashSet<String> set = new HashSet<>();
set.add("Apple");
set.add("Banana");
set.add("Orange");
set.add("Apple"); // 重复元素,不会被添加
System.out.println(set); // 输出 [Orange, Banana, Apple]
}
}
1.3 HashSet 的性能
- 查找、删除和添加的时间复杂度:由于
HashSet
基于哈希表,它的查找、删除和添加操作的平均时间复杂度为 O(1),非常高效。
2. LinkedHashSet 特点
LinkedHashSet
是 HashSet
的一个子类,它结合了哈希表和链表的特点。与 HashSet
相比,LinkedHashSet
的主要特点是维护了元素的插入顺序。
2.1 LinkedHashSet 的基本特点
- 有序:
LinkedHashSet
保证元素的插入顺序,遍历时会按照元素被添加到集合中的顺序返回。 - 不重复:与
HashSet
一样,LinkedHashSet
不允许重复元素。 - 线程不安全:
LinkedHashSet
也是线程不安全的,适用于单线程环境或需要手动同步的场景。
2.2 LinkedHashSet 的底层原理
LinkedHashSet
内部使用了 HashMap
来存储数据,并且使用一个双向链表来维护元素的插入顺序。每次插入元素时,LinkedHashSet
会通过哈希表来保证元素的唯一性,同时通过链表来记录插入顺序。
import java.util.LinkedHashSet;
public class LinkedHashSetExample {
public static void main(String[] args) {
LinkedHashSet<String> set = new LinkedHashSet<>();
set.add("Apple");
set.add("Banana");
set.add("Orange");
System.out.println(set); // 输出 [Apple, Banana, Orange]
}
}
2.3 LinkedHashSet 的性能
- 查找、删除和添加的时间复杂度:
LinkedHashSet
由于是基于哈希表实现的,查找、删除和添加操作的平均时间复杂度为 O(1)。 - 插入顺序:由于
LinkedHashSet
维护了元素的插入顺序,因此它的插入、删除、访问顺序有一定的额外开销。
3. TreeSet 和排序
TreeSet
是 Set
接口的另一个实现类,它基于 TreeMap
实现,元素按自然顺序或自定义顺序进行排序。
3.1 TreeSet 的基本特点
- 有序:
TreeSet
中的元素是有序的,默认按照元素的自然顺序进行排序,也可以通过传入Comparator
对象来实现自定义排序。 - 不重复:与其他
Set
实现一样,TreeSet
也不允许重复元素。 - 线程不安全:
TreeSet
是线程不安全的。
3.2 TreeSet 的底层原理
TreeSet
底层是基于红黑树实现的,红黑树是一种自平衡的二叉查找树,能够保证插入、删除、查找等操作的时间复杂度为 O(log n)。
- 在
TreeSet
中,元素按升序排列(使用Comparable
或Comparator
进行排序)。 - 插入元素时,
TreeSet
会根据元素的大小关系进行位置排序。
import java.util.TreeSet;
public class TreeSetExample {
public static void main(String[] args) {
TreeSet<Integer> set = new TreeSet<>();
set.add(10);
set.add(20);
set.add(5);
set.add(15);
System.out.println(set); // 输出 [5, 10, 15, 20]
}
}
3.3 自定义排序
你可以通过传入自定义的 Comparator
来实现自定义排序规则。例如,按降序排列元素:
import java.util.TreeSet;
import java.util.Comparator;
public class CustomSortExample {
public static void main(String[] args) {
TreeSet<Integer> set = new TreeSet<>(Comparator.reverseOrder());
set.add(10);
set.add(20);
set.add(5);
set.add(15);
System.out.println(set); // 输出 [20, 15, 10, 5]
}
}
3.4 TreeSet 的性能
- 查找、删除和添加的时间复杂度:由于
TreeSet
基于红黑树实现,它的查找、删除和添加操作的时间复杂度为 O(log n),比HashSet
的 O(1) 慢,但它具有排序功能。
4. Set 集合的应用场景
Set
集合广泛应用于需要存储不重复元素的场景,它在以下几种应用中表现得尤为出色:
4.1 数据去重
在处理大量数据时,我们通常需要去重操作。Set
集合可以有效地保证元素不重复。例如,去除列表中的重复元素:
import java.util.HashSet;
import java.util.List;
import java.util.ArrayList;
public class RemoveDuplicatesExample {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Apple");
list.add("Orange");
HashSet<String> set = new HashSet<>(list);
System.out.println(set); // 输出 [Apple, Banana, Orange]
}
}
4.2 统计唯一元素
Set
适用于统计唯一元素。例如,统计一组数据中有多少种不同的元素:
import java.util.HashSet;
public class UniqueElementsExample {
public static void main(String[] args) {
String[] data = {"apple", "banana", "apple", "orange", "banana"};
HashSet<String> set = new HashSet<>();
for (String item : data) {
set.add(item);
}
System.out.println("Unique elements: " + set.size()); // 输出 Unique elements: 3
}
}
4.3 排序元素
如果需要有序的元素(例如按升序或自定义规则排序),可以使用 TreeSet
,它会自动排序。例如,存储一组数字并按升序排序:
import java.util.TreeSet;
public class SortedSetExample {
public static void main(String[] args) {
TreeSet<Integer> set = new TreeSet<>();
set.add(5);
set.add(1);
set.add(9);
set.add(3);
System.out.println(set); // 输出 [1, 3, 5, 9]
}
}
4.4 快速查找和删除
Set
的查找、删除操作通常比 List
更高效,尤其在使用 HashSet
时。它适用于需要频繁查找和删除元素的场景。
总结
- HashSet:基于哈希表实现,存储无序、不可重复的元素,性能高,但不保证顺序。
- LinkedHashSet:继承自
HashSet
,同时保持元素的插入顺序,适用于需要有序存储的场景。 - TreeSet:基于红黑树实现,自动排序,适用于需要排序的场景,但性能稍逊色。
Set
集合的应用非常广泛,特别适用于去重、统计唯一元素、排序和高效查找等场景。在实际开发中,根据具体需求选择合适的 Set
实现类,能够大大提高程序的性能和可维护性。
… …
文末
好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。
… …
学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!
wished for you successed !!!
⭐️若喜欢我,就请关注我叭。
⭐️若对您有用,就请点赞叭。
⭐️若有疑问,就请评论留言告诉我叭。
版权声明:本文由作者原创,转载请注明出处,谢谢支持!
- 点赞
- 收藏
- 关注作者
评论(0)