TreeSet 类、TreeMap 类

概述

1、TreeSet 底层是 TreeMap,维护红黑树

2、相同

(1)有序集合,存储的值都有序,不传入 Comparator 的情况下,默认按键自然排序

(2)非同步集合,不能在多线程之间共享,可以使用方法 Collections.synchroinzedMap() 实现同步

(3)运行速度都要比 Hash 集合慢,内部对元素的操作时间复杂度为 O(logN),而 HashMap / HashSet 则为 O(1)

(4)不允许存储 null,因为它每次添加新元素时,都会比较值,然后进行排序,所以在内部发生的事情是,它将新添加的null值与现有值进行比较,因此它将抛出 NullPointerException

3、不同

(1)TreeSet、TreeMap 分别实现 Set、Map 接口

(2)TreeSet 只存储一个 key,而 TreeMap 存储 key-value(仅 key 对象有序)

(3)TreeSet 中不能有重复对象,而 TreeMap 中 key 不允许重复,value 可以重复

(4)HashMap、HashSet 是由底层决定 key 是否相同,TreeMap、TreeSet 是由传入的 Comparator 或实现 Comparable 的 key 决定 key 是否相同

 

底层

1、无参构造器,根据其元素的自然排序进行排序,所有元素必须实现 Comparable 接口

public TreeSet() {
    this(new TreeMap<E,Object>());
}
public TreeMap() {
    comparator = null;
}

2、有参构造器,传入比较器(匿名内部类)

public TreeSet(Comparator<? super E> comparator) {
    this(new TreeMap<>(comparator));
}
public TreeMap(Comparator<? super K> comparator) {
    this.comparator = comparator;
}

3、添加 key - value

public boolean add(E e) {
    return m.put(e, PRESENT)==null;
}
public V put(K key, V value) {
    Entry<K,V> t = root;
    if (t == null) {
        compare(key, key); // type (and possibly null) check

        root = new Entry<>(key, value, null);
        size = 1;
        modCount++;
        return null;
    }
    int cmp;
    Entry<K,V> parent;
    // split comparator and comparable paths
    Comparator<? super K> cpr = comparator;
    if (cpr != null) {
        do {
            parent = t;
            cmp = cpr.compare(key, t.key);
            if (cmp < 0)
                t = t.left;
            else if (cmp > 0)
                t = t.right;
            else
                return t.setValue(value);
        } while (t != null);
    }
    else {
        if (key == null)
            throw new NullPointerException();
        @SuppressWarnings("unchecked")
        Comparable<? super K> k = (Comparable<? super K>) key;
        do {
            parent = t;
            cmp = k.compareTo(t.key);
            if (cmp < 0)
                t = t.left;
            else if (cmp > 0)
                t = t.right;
            else
                return t.setValue(value);
        } while (t != null);
    }
    Entry<K,V> e = new Entry<>(key, value, parent);
    if (cmp < 0)
        parent.left = e;
    else
        parent.right = e;
    fixAfterInsertion(e);
    size++;
    modCount++;
    return null;
}

(1)判断根节点是否为 null

(2)调用 compare 方法,实际是 key 与自身比较,防止 key 为 null

final int compare(Object k1, Object k2) {
    return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2)
        : comparator.compare((K)k1, (K)k2);
}

(3)cpr 即为传入的比较器,以比较器实现的 compare 方法比较 key,直到叶子节点,若 key 不同,成为新的叶子节点,若 key 相同,替换 value

(4)若根据其元素的自然排序进行排序,key 不能为 null

posted @   半条咸鱼  阅读(46)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示