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(), null, null);
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,V> implements 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的主要内容,如果未能解决你的问题,请参考以下文章