TreeMap 红黑树实现
TreeMap 是一个有序的key-value集合,它是通过 红黑树 实现的。
TreeMap 继承于AbstractMap,所以它是一个Map,即一个key-value集合。
TreeMap 实现了NavigableMap,Cloneable和Serializable接口。

TreeMap的基本操作 containsKey、get、put 和 remove 的时间复杂度是 log(n) 。
首先是TreeMap的构造方法:
public TreeMap() {
comparator = null;
}
/**
* Constructs a new, empty tree map, ordered according to the given comparator.
*/
public TreeMap(Comparator<? super K> comparator) {
this.comparator = comparator;
}
/**
* Constructs a new tree map containing the same mappings as the given
* map, ordered according to the <em>natural ordering</em> of its keys.
*/
public TreeMap(Map<? extends K, ? extends V> m) {
comparator = null;
putAll(m);
}
/**
* Constructs a new tree map containing the same mappings and
* using the same ordering as the specified sorted map. This
* method runs in linear time.
*/
public TreeMap(SortedMap<K, ? extends V> m) {
comparator = m.comparator();
try {
buildFromSorted(m.size(), m.entrySet().iterator(), null, null);
} catch (java.io.IOException cannotHappen) {
} catch (ClassNotFoundException cannotHappen) {
}
}
TreeMap是基于红黑树实现的,以下是树结点的定义,主要key(键)、value(值)、left(左孩子)、right(右孩子)、parent(父节点)、color(颜色)六个字段,根据key的值进行排序。该内部类比较简单,不做分析。
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;
}
......
}
以下是红黑树的插入put和删除deleteEntry操作,以及执行插入删除时需要用到的操作:左旋rotateLeft、右旋rotateRight、插入修正fixAfterInsertion和删除修正fixAfterDeletion。
插入操作,先找到要插入的位置,插入新结点,调用fixAfterInsertion对插入结果进行修正:
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;
}
fixAfterInsertion操作,保证插入节点之后,仍然是一棵红黑树:
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;
}
之中用到了leftRotate和rightRotate操作,这里先介绍这两个操作,在fixAfterDeletion中也会用到:
private void rotateLeft(Entry<K,V> p) {
if (p != null) {
Entry<K,V> r = p.right;
p.right = r.left;
if (r.left != null)
r.left.parent = p;
r.parent = p.parent;
if (p.parent == null)
root = r;
else if (p.parent.left == p)
p.parent.left = r;
else
p.parent.right = r;
r.left = p;
p.parent = r;
}
}
private void rotateRight(Entry<K,V> p) {
if (p != null) {
Entry<K,V> l = p.left;
p.left = l.right;
if (l.right != null)
l.right.parent = p;
l.parent = p.parent;
if (p.parent == null)
root = l;
else if (p.parent.right == p)
p.parent.right = l;
else p.parent.left = l;
l.right = p;
p.parent = l;
}
}
删除操作,先按二叉查找树的方法删除节点,然后调用fixAfterDeletion使得树保持红黑树性质:
private void deleteEntry(Entry<K, V> p) {
modCount++;
size--;
if (p.left != null && p.right != null) {
Entry<K, V> s = successor(p);
p.key = s.key;
p.value = s.value;
p = s;
}
Entry<K,V> replacement = p.left != null ? p.left : p.right;
if (replacement != null) {
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;
p.left = p.right = p.parent = null;
if (p.COLOR == BLACK)
fixAfterDeletion(replacement);
} else if (p.parent == NULL) {
root = null;
} else {
if (p.color == BLACK)
fixAfterDeletion(p);
if (p.parent != null) {
if (p ==p.parent.left)
p.parent.left = null;
else
p.parent.right = null;
p.parent = null;
}
}
}
TreeMap 红黑树实现的更多相关文章
- 通过分析 JDK 源代码研究 TreeMap 红黑树算法实现
本文转载自http://www.ibm.com/developerworks/cn/java/j-lo-tree/ 目录: TreeSet 和 TreeMap 的关系 TreeMap 的添加节点 Tr ...
- 研究jdk关于TreeMap 红黑树算法实现
因为TreeMap的实现方式是用红黑树这种数据结构进行存储的,所以呢我主要通过分析红黑树的实现在看待TreeMap,侧重点也在于如何实现红黑树,因为网上已经有非常都的关于红黑树的实现.我也看了些,但是 ...
- 通过分析 JDK 源代码研究 TreeMap 红黑树算法实现--转
TreeMap 和 TreeSet 是 Java Collection Framework 的两个重要成员,其中 TreeMap 是 Map 接口的常用实现类,而 TreeSet 是 Set 接口的常 ...
- 通过分析 JDK 源代码研究 TreeMap 红黑树算法实
TreeMap和TreeSet是Java Collection Framework的两个重要成员,其中TreeMap是Map接口的常用实现类,而TreeSet是Set接口的常用实现类.虽然HashMa ...
- TreeMap红黑树
Java TreeMap实现了SortedMap接口,也就是说会按照key的大小顺序对Map中的元素进行排序,key大小的评判可以通过其本身的自然顺序(natural ordering),也可以通过构 ...
- 53 容器(八)——TreeMap 红黑树
红黑树是比较难以理解的一种数据结构.它能从10亿数据中进行10几次比较就能查找到需要的数据.效率非常高. 理解起内部结构也难. 现阶段我们知道有这种东西就行了. 参考文章: https://www.j ...
- 红黑树、TreeMap、TreeSet
事先声明以下代码基于JDK1.8版本 参考资料 大部分图片引自https://www.jianshu.com/p/e136ec79235c侵删 https://www.cnblogs.com/skyw ...
- 【深入理解Java集合框架】红黑树讲解(上)
来源:史上最清晰的红黑树讲解(上) - CarpenterLee 作者:CarpenterLee(转载已获得作者许可,如需转载请与原作者联系) 文中所有图片点击之后均可查看大图! 史上最清晰的红黑树讲 ...
- 大数据学习--day17(Map--HashMap--TreeMap、红黑树)
Map--HashMap--TreeMap--红黑树 Map:三种遍历方式 HashMap:拉链法.用哈希函数计算出int值. 用桶的思想去存储元素.桶里的元素用链表串起来,之后长了的话转红黑树. T ...
随机推荐
- hdu3589 Jacobi symbol(二次剩余 数论题)
本题的注意点:n=p1*p2*p3......Pm 解法:直接利用公式a^((p-1)/2)=(a/p)mod p 即可求解. #include<stdio.h> #include< ...
- 提高你的Java代码质量吧:少用静态导入
一.分析 从Java 5开始引入静态导入语法(import static),其目的是为了减少字符输入量,提高代码的可阅读性,以便更好地理解程序. 但是,滥用静态导入会使程序更难阅读,更难维护.静态导 ...
- js判断一个字符串是否在另一个字符串中存在 indexOf
使用indexOf来实现.当返回值为-1时表示不存在. 举例: var href = 'www.51qdq.com';alert(href.indexOf('test')); //返回值 -1aler ...
- Linux开发环境搭建与使用——ubuntu更新设置
ubuntu操作系统公布时,为了减小操作系统的体积,只配备了主要的系统软件.应用软件.我们开发中须要用到的大部分软件都须要在使用中从网上自行更新. 假设ubuntu没有网络,能够说寸步难行. 以下教大 ...
- MyEclipse设置默认的目光格式
首先,选择菜单 windows-->preference Java-->Code Style-->Code Templates code-->new Java files 然后 ...
- 解决FLASH最高层的问题,让FLASH置于div之下
三个步骤:1.设置div 的 z-index:9999 //在最上面显示 这一步就可以保证div在img之上2.<param name="wmode" value=" ...
- 如何把 excel 设为文本格式?
选择要设置的单元格,右键选择 --- “设置单元格格式” --- 选 “ 分类 ” 下面的 “ 文本 ” --- 确定. 修改前: 修改后:
- C# 重新改变数组的长度
重新改变数组的长度 System.Array.Resize(ref FieldName, j);
- 自定义ZXing二维码扫描界面并解决取景框拉伸等问题
先看效果 扫描内容是下面这张,二维码是用zxing库生成的 由于改了好几个类,还是去年的事都忘得差不多了,所以只能上这个类的代码了,主要就是改了这个CaptureActivity.java packa ...
- 封装,capsulation,&&继承,Inheritance,&&多态,polymorphism
Inheritance&&polymorphism 层次概念是计算机的重要概念.通过继承(inheritance)的机制可对类(class)分层,提供类型/子类型的关系.C++通过类派 ...