TreeMap使用
TreeMap存储K-V键值对,通过红黑树(R-B tree)实现;
TreeMap继承了NavigableMap接口,NavigableMap接口继承了SortedMap接口,可支持一系列的导航定位以及导航操作的方法,当然只是提供了接口,需要TreeMap自己去实现;
TreeMap实现了Cloneable接口,可被克隆,实现了Serializable接口,可序列化;
TreeMap因为是通过红黑树实现,红黑树结构天然支持排序,默认情况下通过Key值的自然顺序进行排序;
TreeMap根据Key来进行排序,如果不是对象,自然排序,如果是对象:
- 在构造函数中传入比较器comparator,用comparator来比较元素的Key,用于排序
- 或者key的对象实现Comparable,用Comparable的比较方法进行比较key
这东西本质上,就是比较key,然后用红黑树进行存储,查找
key对象实现Comparable代码示例


用comparator比较器的代码示例
如果同时实现了comparator和Comparable,comparator优先级高
红黑树底层原理
由于TreeMap底层使用红黑树处理,想要了解内容必须先了解红黑树,但红黑树还需要知晓二叉树,平衡二叉树,2-3-4树的原理,可以看以下文章用于参考
sheng的学习笔记-二叉树(BST)_coldstarry的博客-优快云博客
sheng的学习笔记-平衡二叉树(AVL)和3+4重构_coldstarry的博客-优快云博客
sheng的学习笔记-2-3查找树_coldstarry的博客-优快云博客
sheng的学习笔记-红黑树_coldstarry的博客-优快云博客
TreeMap和HashMap比较:
(1)HashMap:适用于在Map中插入、删除和定位元素。
(2)Treemap:适用于按自然顺序或自定义顺序遍历键(key)。
(3)HashMap通常比TreeMap快一点(树和哈希表的数据结构使然),正常可以使用HashMap,在需要排序的Map时候才用TreeMap. HashMap的时间复杂度是O(1),是通过哈希函数计算的哈希地址。而我们的红黑树就不具有这样的优势时间复杂度是O(log2 n)
(4)HashMap 非线程安全 TreeMap 非线程安全
(5)HashMap的结果是没有排序的,而TreeMap输出的结果是排好序的。
上面是拷过来的,总体来说HashMap底层是哈希桶(无序),TreeMap底层是红黑树(根据key排序,有序),如果想要KEY=>VALUE使用,可以用HashMap
代码解析
内部节点,comparator如果有,用于比较key值。用root存放红黑树

插入元素
起手式这个if就是根据comparator比较元素,如果没比较器,用comparable比较,使用的是红黑树的查找方式,找到需要插入新元素的位置,比如计划插入到叶子结点t的下面,此时t节点的left/right是空的,跳出while循环,但需要记住t节点,所以用Parent = t;这行代码
private V put(K key, V value, boolean replaceOld) {
Entry<K,V> t = root;
if (t == null) {
addEntryToEmptyMap(key, value);
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 {
V oldValue = t.value;
if (replaceOld || oldValue == null) {
t.value = value;
}
return oldValue;
}
} while (t != null);
} else {
Objects.requireNonNull(key);
@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 {
V oldValue = t.value;
if (replaceOld || oldValue == null) {
t.value = value;
}
return oldValue;
}
} while (t != null);
}
addEntry(key, value, parent, cmp < 0);
return null;
}
插入数据,addToLeft就是新节点比父节点大还是小,用于决定插入左边还是右边,插入完成后要进行红黑树的重新染色和旋转
这就是重新染色和旋转了,具体的看红黑树部分,不细说了,看下面的博客或者自己找下博客看看
sheng的学习笔记-红黑树_coldstarry的博客-优快云博客
private void fixAfterInsertion(Entry<K,V> x) {
x.color = RED;
while (x != null && x != root && x.parent.color == RED) {
if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
Entry<K,V> y = rightOf(parentOf(parentOf(x)));
if (colorOf(y) == RED) {
setColor(parentOf(x), BLACK);
setColor(y, BLACK);
setColor(parentOf(parentOf(x)), RED);
x = parentOf(parentOf(x));
} else {
if (x == rightOf(parentOf(x))) {
x = parentOf(x);
rotateLeft(x);
}
setColor(parentOf(x), BLACK);
setColor(parentOf(parentOf(x)), RED);
rotateRight(parentOf(parentOf(x)));
}
} else {
Entry<K,V> y = leftOf(parentOf(parentOf(x)));
if (colorOf(y) == RED) {
setColor(parentOf(x), BLACK);
setColor(y, BLACK);
setColor(parentOf(parentOf(x)), RED);
x = parentOf(parentOf(x));
} else {
if (x == leftOf(parentOf(x))) {
x = parentOf(x);
rotateRight(x);
}
setColor(parentOf(x), BLACK);
setColor(parentOf(parentOf(x)), RED);
rotateLeft(parentOf(parentOf(x)));
}
}
}
root.color = BLACK;
}
查找元素

查找元素就是个标准的二叉树查找(二叉树的查找和红黑树的查找一样,因为在查找时与节点的颜色无关) 。右比较器,通过比较器比较,否则通过comparable比较

删除元素
先查找,再删除,删除中包括元素删除和重新染色,旋转
删除逻辑
private void deleteEntry(Entry<K,V> p) {
modCount++;
size--;
// If strictly internal, copy successor's element to p and then make p
// point to successor.
if (p.left != null && p.right != null) {
Entry<K,V> s = successor(p);
p.key = s.key;
p.value = s.value;
p = s;
} // p has 2 children
// Start fixup at replacement node, if it exists.
Entry<K,V> replacement = (p.left != null ? p.left : p.right);
if (replacement != null) {
// Link replacement to parent
replacement.parent = p.parent;
if (p.parent == null)
root = replacement;
else if (p == p.parent.left)
p.parent.left = replacement;
else
p.parent.right = replacement;
// Null out links so they are OK to use by fixAfterDeletion.
p.left = p.right = p.parent = null;
// Fix replacement
if (p.color == BLACK)
fixAfterDeletion(replacement);
} else if (p.parent == null) { // return if we are the only node.
root = null;
} else { // No children. Use self as phantom replacement and unlink.
if (p.color == BLACK)
fixAfterDeletion(p);
if (p.parent != null) {
if (p == p.parent.left)
p.parent.left = null;
else if (p == p.parent.right)
p.parent.right = null;
p.parent = null;
}
}
}
删除后重新染色逻辑
private void fixAfterDeletion(Entry<K,V> x) {
while (x != root && colorOf(x) == BLACK) {
if (x == leftOf(parentOf(x))) {
Entry<K,V> sib = rightOf(parentOf(x));
if (colorOf(sib) == RED) {
setColor(sib, BLACK);
setColor(parentOf(x), RED);
rotateLeft(parentOf(x));
sib = rightOf(parentOf(x));
}
if (colorOf(leftOf(sib)) == BLACK &&
colorOf(rightOf(sib)) == BLACK) {
setColor(sib, RED);
x = parentOf(x);
} else {
if (colorOf(rightOf(sib)) == BLACK) {
setColor(leftOf(sib), BLACK);
setColor(sib, RED);
rotateRight(sib);
sib = rightOf(parentOf(x));
}
setColor(sib, colorOf(parentOf(x)));
setColor(parentOf(x), BLACK);
setColor(rightOf(sib), BLACK);
rotateLeft(parentOf(x));
x = root;
}
} else { // symmetric
Entry<K,V> sib = leftOf(parentOf(x));
if (colorOf(sib) == RED) {
setColor(sib, BLACK);
setColor(parentOf(x), RED);
rotateRight(parentOf(x));
sib = leftOf(parentOf(x));
}
if (colorOf(rightOf(sib)) == BLACK &&
colorOf(leftOf(sib)) == BLACK) {
setColor(sib, RED);
x = parentOf(x);
} else {
if (colorOf(leftOf(sib)) == BLACK) {
setColor(rightOf(sib), BLACK);
setColor(sib, RED);
rotateLeft(sib);
sib = leftOf(parentOf(x));
}
setColor(sib, colorOf(parentOf(x)));
setColor(parentOf(x), BLACK);
setColor(leftOf(sib), BLACK);
rotateRight(parentOf(x));
x = root;
}
}
}
setColor(x, BLACK);
}
参考文章:
本文深入剖析了TreeMap的数据结构和工作原理,重点介绍了红黑树的使用,并对比了TreeMap与HashMap的区别,包括排序、性能及线程安全性等方面。
1万+

被折叠的 条评论
为什么被折叠?



