TreeSet、HashSet、LinkedHashSet

本文详细解析了TreeSet与HashSet的内部实现原理,包括TreeSet如何利用TreeMap进行排序及逆序迭代,以及HashSet如何基于HashMap实现元素的存储。同时介绍了LinkedHashSet的特点。

一、类图

       

二、要点

1.  TreeSet 是基于 TreeMap 实现的,内置了 NavigableMap,构造函数直接使用 TreeMap

    /**
     * The backing map.
     */
    private transient NavigableMap<E,Object> m;

    /**
     * Constructs a new, empty tree set, sorted according to the
     * natural ordering of its elements.  All elements inserted into
     * the set must implement the {@link Comparable} interface.
     * Furthermore, all such elements must be <i>mutually
     * comparable</i>: {@code e1.compareTo(e2)} must not throw a
     * {@code ClassCastException} for any elements {@code e1} and
     * {@code e2} in the set.  If the user attempts to add an element
     * to the set that violates this constraint (for example, the user
     * attempts to add a string element to a set whose elements are
     * integers), the {@code add} call will throw a
     * {@code ClassCastException}.
     */
    public TreeSet() {
        this(new TreeMap<E,Object>());
    }

    /**
     * Constructs a new, empty tree set, sorted according to the specified
     * comparator.  All elements inserted into the set must be <i>mutually
     * comparable</i> by the specified comparator: {@code comparator.compare(e1,
     * e2)} must not throw a {@code ClassCastException} for any elements
     * {@code e1} and {@code e2} in the set.  If the user attempts to add
     * an element to the set that violates this constraint, the
     * {@code add} call will throw a {@code ClassCastException}.
     *
     * @param comparator the comparator that will be used to order this set.
     *        If {@code null}, the {@linkplain Comparable natural
     *        ordering} of the elements will be used.
     */
    public TreeSet(Comparator<? super E> comparator) {
        this(new TreeMap<>(comparator));
    }

2.  TreeSet 提供逆序迭代 descendingSet

3.  TreeSet 内部实现都是委托给 TreeMap 实现了

    public boolean contains(Object o) {
        return m.containsKey(o);
    }

4.   HashSet 是基于 HashMap 实现的

    public HashSet() {
        map = new HashMap<>();
    }

5.   LinkedHashSet 基于 HashMap 的子类 LinkedHashMap 实现

    public LinkedHashSet(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor, true);
    }

    // super method

    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
        map = new LinkedHashMap<>(initialCapacity, loadFactor);
    }  

<think>我们被要求回答HashSetLinkedHashSetTreeSet的区别。根据之前的引用内容,我们可以从以下几个方面进行对比: 1. 底层实现 2. 元素唯一性 3. 元素排序/顺序特性 4. 性能比较(插入、删除、查找) 5. 适用场景 此外,我们还需要注意回答的结构,使用适当的标题,并在最后生成相关问题。 根据引用[1][2][3][4]的内容,我们可以总结如下: 1. 底层实现: - HashSet: 基于HashMap实现,使用哈希表(数组+链表/红黑树)。 - LinkedHashSet: 继承自HashSet,底层使用LinkedHashMap,维护了一个双向链表来记录插入顺序。 - TreeSet: 基于TreeMap实现,使用红黑树(自平衡二叉查找树)。 2. 元素唯一性:三者都实现了Set接口,因此都不允许重复元素。 3. 元素排序/顺序特性: - HashSet:无序,不保证元素的任何顺序(迭代顺序可能变化)。 - LinkedHashSet:按照元素插入的顺序进行排序(即插入顺序)。 - TreeSet:按照元素的自然顺序(实现Comparable接口)或者根据提供的Comparator进行排序(树的有序结构保证)。 4. 性能比较: - HashSet:插入、删除和查找操作的时间复杂度通常为$O(1)$(在哈希函数分散均匀的情况下)。 - LinkedHashSet:由于需要维护双向链表,性能略低于HashSet,但迭代顺序可预测,且迭代性能比HashSet好(因为链表连接了所有元素)。 - TreeSet:插入、删除和查找操作的时间复杂度为$O(\log n)$,因为需要维护红黑树的平衡。 5. 允许null值: - HashSetLinkedHashSet允许一个null元素。 - TreeSet不允许null元素(因为需要比较,null无法比较)。 6. 线程安全:三者都不是线程安全的。 7. 适用场景: - HashSet:当不需要维护顺序,只需要高效地添加、删除和判断元素是否存在时使用。 - LinkedHashSet:当需要维护元素的插入顺序时使用。 - TreeSet:当需要元素按照排序顺序(升序或降序)时使用。 我们按照以上要点组织答案。 </think>### HashSetLinkedHashSetTreeSet的核心区别 以下是Java中三种Set实现的对比总结,涵盖底层实现、排序特性、性能表现和适用场景: | **特性** | **HashSet** | **LinkedHashSet** | **TreeSet** | |------------------|--------------------------------|--------------------------------------|--------------------------------| | **底层实现** | 基于`HashMap`(哈希表+链表/红黑树) | 继承`HashSet`,底层为`LinkedHashMap`(哈希表+双向链表) | 基于`TreeMap`(红黑树) | | **元素唯一性** | ✅ 不允许重复元素 | ✅ 不允许重复元素 | ✅ 不允许重复元素 | | **排序特性** | ❌ 完全无序 | ✅ 保留插入顺序 | ✅ 自然排序或自定义排序(`Comparator`) | | **`null`支持** | ✅ 允许1个`null`元素 | ✅ 允许1个`null`元素 | ❌ 禁止`null`(需可比较) | | **时间复杂度** | $O(1)$(理想情况) | $O(1)$(操作略慢于`HashSet`) | $O(\log n)$(所有操作) | | **内存开销** | 较低(仅哈希表) | 较高(额外维护链表指针) | 较高(红黑树结构) | | **线程安全** | ❌ 非线程安全 | ❌ 非线程安全 | ❌ 非线程安全 | #### 详细解析 1. **底层实现与排序差异** - **HashSet**:通过`hashCode()`定位存储桶位置,迭代顺序不可预测(如`[A,C,B]`)。 - **LinkedHashSet**:在`HashSet`基础上增加双向链表,严格保持插入顺序(如`[A,B,C]`)[^1][^4]。 - **TreeSet**:通过红黑树实现自动排序(默认自然顺序,如字母升序`[A,B,C]`),可自定义`Comparator`[^3]。 2. **性能对比** - **插入/查找效率**: - `HashSet` ≈ `LinkedHashSet` > `TreeSet` - 原因:`HashSet`和`LinkedHashSet`基于哈希表(常数时间),`TreeSet`需维护红黑树平衡(对数时间)[^3]。 - **迭代效率**: - `LinkedHashSet` > `TreeSet` > `HashSet` - 原因:`LinkedHashSet`链表遍历直接有序,`TreeSet`中序遍历有序,`HashSet`需扫描全部哈希桶[^2]。 3. **适用场景建议** - **HashSet**:高频读写场景,不关心顺序(如去重统计)。 ```java Set<String> cache = new HashSet<>(); // 网页URL去重缓存 ``` - **LinkedHashSet**:需保留操作历史的场景(如用户操作记录)。 ```java Set<String> userActions = new LinkedHashSet<>(); // 记录用户点击顺序 ``` - **TreeSet**:需动态排序的场景(如排行榜)。 ```java Set<Integer> highScores = new TreeSet<>(Comparator.reverseOrder()); // 游戏分数降序 ``` #### 关键注意事项 - **哈希碰撞影响**:`HashSet`和`LinkedHashSet`性能受`hashCode()`质量影响,碰撞过多会导致退化为$O(n)$[^3]。 - **线程安全方案**:三者均非线程安全,推荐: ```java Set<String> safeSet = Collections.synchronizedSet(new HashSet<>()); // 同步包装 Set<String> concurrentSet = new ConcurrentSkipListSet<>(); // 并发有序集合 ``` - **扩展选择**: - 需线程安全+排序 → `ConcurrentSkipListSet` - 需高并发+无序 → `CopyOnWriteArraySet`
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值