内部结构图
通常称之为红黑树(平衡二叉树)(红黑树(平衡二叉树)是一种特殊的排序二叉树)
实现原理
由于红黑树过于复杂,下诉实现原理只是排序二叉树的原理,红黑树以此类似。
TreeMap内部维护着一个Entry<K,V>
对象,该对象包含五个属性,
K key; 调用put方法的时候传的key
V value; 调用put方法的时候传的value
Entry<K,V> left = null; 左节点
Entry<K,V> right = null; 右节点
Entry<K,V> parent; 父节点
boolean color = BLACK; 节点颜色
当我们往TreeMap中put值时,第一个put的值会作为跟节点,往后put的值会拿put的key和根节点的key做比较,如果新key>根key,则拿新key和根节点的右节点做比较,如果小于,则又和左节点做比较,如果等于,则替换节点的值,直到节点为null,就把新的作为此节点,如此反复,就会形成图中的结构。
关于红黑树:这种排序二叉树在极端情况下(程序员本身插入的key就是有序的)(比如我们插入的key是abcdefg…)的时候,就有可能形成
这种链状引用,这个时候进行检索效率是非常低下的(类似于链状结构检索),所以为了解决这个问题,java中的TreeMap使用的是红黑树结构,红黑树具体实现原理过于复杂,涉及树的旋转之类。本文不诉,具体是当我们插入的是abcdefg这种本身就是有序的,形成的结构不是引用的,而是类似于
这种相对平衡的结构。这样检索的时候就相对较快。
特点
1.有序,顺序是根据插入的key的顺序来排的。
2.无法插入null的key
3.TreeMap通常比HashMap慢一点(树和哈希表的数据结构使然)
常用方法源码
put(K key, V value)
public V put(K key, V value) {
Entry<K,V> t = root;
if (t == null) {
compare(key, key); //检查key不能为null
root = new Entry<>(key, value, null);//第一次put的时候创建根节点
size = 1;
modCount++;
return null;
}
int cmp;
Entry<K,V> parent;
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 {//递归比较新key是放入左节点还是右节点
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;
}
get(Object key)
public V get(Object key) {
Entry<K,V> p = getEntry(key);
return (p==null ? null : p.value);
}
final Entry<K,V> getEntry(Object key) {
// Offload comparator-based version for sake of performance
if (comparator != null)
return getEntryUsingComparator(key);
if (key == null)
throw new NullPointerException();
Comparable<? super K> k = (Comparable<? super K>) key;
Entry<K,V> p = root;
while (p != null) {//递归直到找到对应的元素
int cmp = k.compareTo(p.key);
if (cmp < 0)
p = p.left;
else if (cmp > 0)
p = p.right;
else
return p;
}
return null;
}