1、概述
TreeMap是Java内部实现比较复杂的集合类之一。与HashMap不一样,TreeMap的底层不是用哈希表实现的,而是用红黑树实现的。另外,HashMap存取元素的时间复杂度是O(1)的常量级,而TreeMap对元素的操作复杂度为O(log n)。虽然在操作性能方面,TreeMap不占优势,但是因为它使用红黑树(平衡二叉查找树)实现,所以它内部的元素都是排好序的。当需要查找的元素是排好序的,TreeMap的优势就体现出来了。
2、红黑树简介
首先,介绍一下红黑树的基本性质。红黑树不是一棵严格意义上的平衡树,因为它的高度差会大于1。了解一下它的性质就清楚了。
红黑树是一棵二叉树,它满足以下5个特性:
<1>每个节点的颜色是红色或黑色。
<2>根节点必须是黑色的。
<3>每个叶节点是黑色的(叶节点是指树尾端的NULL节点)。
<4>如果一个节点是红色的,那么它的子节点必须是黑色。即,不能有连续的红色节点。
<5>对于任意一个节点,从它到叶节点的每条路径包含相同数量的黑色节点。
由上述定义可知,红黑树是一棵相对平衡的二叉查找树。因为红黑树天生需要平衡,所以就可以避免一般的二叉查找树在极端情况(插入的数据已经排好序)失去平衡的情况。
3、TreeMap的Entry类
由于TreeMap包含了tree和Map的性质,它所包含的的Entry类应该有以下6个成员变量:
左子结点引用、右子节点引用、父节点引用、key、value、color。
在JDK中,Entry的具体定义如下:
static final class Entry<K,V> implements Map.Entry<K,V> { K key; V value; Entry<K,V> left = null; Entry<K,V> right = null; Entry<K,V> parent; boolean color = BLACK; /** * Make a new cell with given key, value, and parent, and with * {@code null} child links, and BLACK color. */ Entry(K key, V value, Entry<K,V> parent) { this.key = key; this.value = value; this.parent = parent; } }
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(); 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; }