JDK源码TreeMap

Posted 未赋值

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JDK源码TreeMap相关的知识,希望对你有一定的参考价值。

JDK8的TreeMap

TreeMap内部是用红黑树实现的,红黑树是一种大致平衡的排序二叉树。所谓大致平衡,它确保任意一条从根节点到叶子节点的路径,没有任意一条路径的长度会比其他路径长过2倍。红黑树减弱了对平衡的要求,但是降低了保持平衡需要的开销,在实际应用中,统计性能高于AVL树。

构造方法

一、默认构造方法,如果使用默认构造方法,要求Map中的键实现Comparable接口,TreeMap内部进行各种比较会调用键的Comparable接口中的comparaTo方法。

1public TreeMap() {
2        comparator = null;
3}

二、接受一个比较器对象comparator。

1public TreeMap(Comparator<? super K> comparator) {
2        this.comparator = comparator;
3}

三、接受一个Map

1public TreeMap(Map<? extends K, ? extends V> m) {
2        comparator = null;
3        putAll(m);
4}

四、接受一个SortedMap,比较器继承SortedMap的比较器

1public TreeMap(SortedMap<K, ? extends V> m{
2        comparator = m.comparator();
3        try {
4            buildFromSorted(m.size(), m.entrySet().iterator(), nullnull);
5        } catch (java.io.IOException cannotHappen) {
6        } catch (ClassNotFoundException cannotHappen) {
7        }
8}

实现原理

TreeMap内部是用红黑树实现的,红黑树是一种大致平衡的排序二叉树。

内部组成

TreeMap内部主要有如下成员:

 1    /**
2     * The comparator used to maintain order in this tree map, or
3     * null if it uses the natural ordering of its keys.
4     */

5    private final Comparator<? super K> comparator;
6
7    //根节点
8    private transient Entry<K,V> root;
9
10    /**
11     * 当前键值对个数
12     */

13    private transient int size = 0;
14
15    /**
16     * 结构性变化次数
17     */

18    private transient int modCount = 0;

Entry

每个节点除了键和值之外,还分别指向左孩子、右孩子和父节点,以及颜色属性color.

 1// Red-black mechanics
2
3    private static final boolean RED   = false;
4    private static final boolean BLACK = true;
5
6    /**
7     * 红黑树节点
8     */

9    static final class Entry<K,Vimplements Map.Entry<K,V{
10        K key;
11        V value;
12        Entry<K,V> left;
13        Entry<K,V> right;
14        Entry<K,V> parent;
15        boolean color = BLACK;
16        /**
17         * Make a new cell with given key, value, and parent, and with
18         * {@code null} child links, and BLACK color.
19         */

20        Entry(K key, V value, Entry<K,V> parent) {
21            this.key = key;
22            this.value = value;
23            this.parent = parent;
24        }

保存键值对

 1public V put(K key, V value) {
2        Entry<K,V> t = root;//从根节点开始比较
3        if (t == null) {//如果是当前没有节点,添加第一个节点
4            compare(key, key); //检查key的类型和null,如果类型不匹配或者为null,compare方法会抛出异常。
5
6            root = new Entry<>(key, value, null);
7            size = 1;
8            modCount++;
9            return null;
10        }
11       /**
12         *如果树中已经有节点,执行下面的代码寻找父节点。
13         */

14        int cmp;//cmp保存比较结果
15        Entry<K,V> parent;
16        // 分两种情况
17        Comparator<? super K> cpr = comparator;
18        if (cpr != null) { //设置了比较器
19            do {//寻找父节点是一个从根节点开始循环的过程
20                parent = t;
21                cmp = cpr.compare(key, t.key);
22                if (cmp < 0)
23                    t = t.left;
24                else if (cmp > 0)
25                    t = t.right;
26                else//比较结果为0,表示已经有这个键了,设置值,然后返回。
27                    return t.setValue(value);
28            } while (t != null); //t为null或者比较结果为0,while循环结束,parent就是要找的父节点
29        }
30        else { //使用默认Comparable的compareTo方法,和上面的逻辑基本一样。
31            if (key == null)
32                throw new NullPointerException();
33            @SuppressWarnings("unchecked")
34                Comparable<? super K> k = (Comparable<? super K>) key;
35            do {
36                parent = t;
37                cmp = k.compareTo(t.key);
38                if (cmp < 0)
39                    t = t.left;
40                else if (cmp > 0)
41                    t = t.right;
42                else
43                    return t.setValue(value);
44            } while (t != null);//使用while循环比较
45        }
46
47        //找到父节点后,创建新节点,根据新的键与父节点的比较结果,插入作为左孩子或者右孩子,并增加size和modCount
48        Entry<K,V> e = new Entry<>(key, value, parent);
49        if (cmp < 0)
50            parent.left = e;
51        else
52            parent.right = e;
53
54        fixAfterInsertion(e);//调整树的结构,使之符合红黑树的约束,保持大致平衡。
55        size++;//节点数加1
56        modCount++;//结构性修改次数加1
57        return null;
58    }

根据键获取值

get方法

1public V get(Object key{
2        Entry<K,V> p = getEntry(key);
3        return (p==null ? null : p.value);
4}

getEntry方法

根据key寻找节点

 1final Entry<K,V> getEntry(Object key) {
2        // Offload comparator-based version for sake of performance
3        if (comparator != null)//如果comparator不为空,调用单独的方法getEntryUsingComparator
4            return getEntryUsingComparator(key);
5        if (key == null)
6            throw new NullPointerException();
7        @SuppressWarnings("unchecked")
8            Comparable<? super K> k = (Comparable<? super K>) key;//假设key实现了Comparable接口,使用compareTo方法进行比较
9        Entry<K,V> p = root;
10        while (p != null) {//从根节点开始比较,根节点不为空,一直循环比较。
11            int cmp = k.compareTo(p.key);
12            if (cmp < 0)
13                p = p.left;
14            else if (cmp > 0)
15                p = p.right;
16            else
17                return p;
18        }
19        return null;
20  }




以上是关于JDK源码TreeMap的主要内容,如果未能解决你的问题,请参考以下文章

JDK1.8源码分析之TreeMap

JDK源码TreeMap

jdk源码分析——TreeMap

集合之TreeSet(含JDK1.8源码分析)

JDK集合 TreeMap

集合类源码Map(ConcurrentHashMap, ConcurrentSkipListMap, TreeMap)