HashSet 和 TreeSet 分别是如何实现去重的
- HashSet 的去重
- TreeSet 的去重
- HashSet 和 TreeSet 的去重原理对比
HashSet 的去重
HashSet
依赖 HashMap
来实现去重。HashSet
是基于哈希表的数据结构,因此它使用对象的哈希值来判断元素的唯一性。
-
底层结构
HashSet
的底层是使用一个HashMap
实现的。HashSet
实际上将元素存储在一个HashMap
的键(key)上,而所有的值(value)都是一个固定的常量对象PRESENT
。- 因此,
HashSet
中的每一个元素相当于HashMap
中的一对key-value
对,其中key
是我们存储的对象,value
是一个单一的对象(通常是PRESENT
)。
-
hashCode 和 equals 方法
- 当向
HashSet
中添加一个新元素时,首先会调用该对象的hashCode()
方法,计算出哈希码,用于判断它在哈希表中的位置。 - 这意味着如果两个对象的
hashCode()
值不同,它们一定被认为是不同的对象,直接添加。 - 如果哈希码相同,那么可能发生哈希冲突,
HashSet
会进一步调用equals()
方法来判断这两个对象是否真的相等。- 如果
equals()
方法返回true
,表示这两个对象相等,新对象不会被添加。 - 如果
equals()
方法返回false
,即便它们的哈希码相同(哈希冲突),新对象仍然会被添加。
- 如果
- 当向
-
结论
- 总的来说,
HashSet
是通过哈希码(hashCode()
方法)来快速确定元素位置,并通过equals()
方法来确保元素不重复。哈希码用于初步筛选,equals()
用于精确比较。 - 因此,
HashSet
的性能相对较高,尤其是在查找和插入时,因为哈希表的查找复杂度是接近O(1)
的。
- 总的来说,
TreeSet 的去重
TreeSet
是基于红黑树的数据结构,它依赖自然排序或者比较器来确保元素不重复,并保持元素的有序性。
-
底层结构
TreeSet
的底层是基于TreeMap
实现的,具体来说是一个红黑树。- 红黑树是一种自平衡的二叉搜索树,可以确保每次添加元素时树的高度保持平衡,从而保证较好的性能。
TreeSet
中的元素是按一定顺序排序的。
-
元素比较
TreeSet
的去重依赖于元素之间的比较,而不是哈希值。在添加元素时,TreeSet
需要使用比较逻辑来判断新元素是否与树中的某个元素相同。- 如果元素实现了
Comparable
接口(例如String
、Integer
),那么TreeSet
会调用元素的compareTo()
方法来比较两个元素的大小。- 如果
compareTo()
返回0
,表示这两个元素是相等的,新元素不会被添加。 - 如果返回负数或正数,则表示元素的相对顺序,
TreeSet
会按照这个顺序将新元素插入到正确的位置。
- 如果
- 如果元素没有实现
Comparable
,用户可以自定义一个Comparator
,并将其传递给TreeSet
的构造方法。TreeSet
会使用这个比较器来判断元素的相等性。 - 因此,在
TreeSet
中,两个对象是通过compareTo()
或者Comparator
的compare()
方法返回值来判断是否相等的。
-
结论
TreeSet
的去重是基于比较逻辑实现的,它通过比较器或者对象的自然排序来判断元素的唯一性。TreeSet
中的查找、插入和删除操作的复杂度是O(log n)
,因为它使用的是红黑树结构。
HashSet 和 TreeSet 的去重原理对比
集合类型 | 去重机制 | 底层实现 | 比较依据 | 时间复杂度(插入/查找) |
---|---|---|---|---|
HashSet | hashCode 和 equals 方法 | 哈希表(HashMap ) | 哈希值和相等判断 | 平均 O(1) |
TreeSet | 比较器或 Comparable | 红黑树(TreeMap ) | 自然排序或 Comparator | O(log n) |
HashSet
适合需要快速查找的场景,但它无法保证元素的顺序。TreeSet
适合需要有序存储的场景,它的插入和查找性能略低于HashSet
。
如果需要保持有序性(例如按字母顺序或数值大小),则使用 TreeSet
;
如果不关心元素的顺序且更关注性能,使用 HashSet
更合适。