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 ...
随机推荐
- Css基础-介绍及语法
css 文件后缀.css 基础语法: selector { property:value } 例如: h1 {color:red;font-size:14px;} color:字体颜色 font-s ...
- openssl enc 加解密
国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html内部邀请码:C8E245J (不写邀请码,没有现金送)国内私 ...
- 重启PHP命令
php-fpm重启 killall php-fpm 再执行(usr/local/php是php的安装目录)/usr/local/php/sbin/php-fpm & /usr/local/ng ...
- cdoj 383 japan 树状数组
Japan Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/problem/show/383 Descrip ...
- 访谈将源代码的函数 strcpy/memcpy/atoi/kmp/quicksort
一.社论 继上一次发表了一片关于參加秋招的学弟学妹们怎样准备找工作的博客之后,反响非常大.顾在此整理一下,以便大家复习.好多源自july的这篇博客,也有非常多是我自己整理的.希望大家可以一遍一遍的写. ...
- Spring MVC page render时jsp中元素相对路径的解决办法
前段时间做了用Spring Security实现的登录和访问权限控制的功能,但是page render使用的是InternalResourceResolver,即在spring的servlet配置文件 ...
- java_jdbc_利用结果集元数据将查询结果封装为map_MetaData
package cn.itcast.batch; import java.sql.Connection; import java.sql.ParameterMetaData; import java. ...
- 使用apache common-io 监控文件变化--转
package common.io; import org.apache.commons.io.filefilter.FileFilterUtils; import org.apache.common ...
- XMl解析之Pull解析
HttpUtils: package cn.qf.parser; import java.io.BufferedOutputStream; import java.io.FileOutputStrea ...
- 简书APP
找第三方的时候看到简书这个APP,上网搜了一下发现网页版非常的干净,开头的一篇文章就是"你没实力就别心存侥幸",看完也挺有有同感的.文章网址:http://www.jianshu. ...