TreeMap的实现基于红黑树,排列的顺序根据key的大小,或者在创建时提供的比较器,取决于使用哪个构造器。

对于,containsKey,get,put,remove操作,保证时间复杂度为log(n)。

TreeMap的顺序与equals方法保持一致,这样才能遵守Map和SortMap的约定。

实现非同步,运行在多线程环境下,要进行外部同步,或者调用SortedMap m = Collections.synchronizedSortedMap(new TreeMap(...));方法得到一个同步化的TreeMap。

迭代器是快速失败的。

//AbstractMap实现Map接口,NavigableMap实现SortedMap接口,为了遵守约定,key的equals方法和客户提供的比较器或者key本身的compare结果要一致
public class TreeMap<K,V>
extends AbstractMap<K,V>
implements NavigableMap<K,V>, Cloneable, java.io.Serializable

实例变量:

//客户提供的比较器,如果不提供,为null
private final Comparator<? super K> comparator; //TreeMap的根结点
private transient Entry<K,V> root = null; //TreeMap含有的结点数
private transient int size = 0; //TreeMap的修改次数,用于迭代器快速失败机制
private transient int modCount = 0;

TreeMap的红黑树结点实现

//结点颜色
private static final boolean RED = false;
private static final boolean BLACK = true; //TreeMap的红黑树结点实现
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;
} /**
* Returns the key.
*
* @return the key
*/
public K getKey() {
return key;
} /**
* Returns the value associated with the key.
*
* @return the value associated with the key
*/
public V getValue() {
return value;
} /**
* Replaces the value currently associated with the key with the given
* value.
*
* @return the value associated with the key before this method was
* called
*/
public V setValue(V value) {
V oldValue = this.value;
this.value = value;
return oldValue;
} public boolean equals(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry<?,?> e = (Map.Entry<?,?>)o; return valEquals(key,e.getKey()) && valEquals(value,e.getValue());
} public int hashCode() {
int keyHash = (key==null ? 0 : key.hashCode());
int valueHash = (value==null ? 0 : value.hashCode());
return keyHash ^ valueHash;
} public String toString() {
return key + "=" + value;
}
}

4个构造器

    //不提供比较器,使用key的自然顺序
public TreeMap() {
comparator = null;
} //提供比较器
public TreeMap(Comparator<? super K> comparator) {
this.comparator = comparator;
} //使用m构造TreeMap,m没有比较器,所以还是使用key的自然顺序
public TreeMap(Map<? extends K, ? extends V> m) {
comparator = null;
putAll(m);
} //使用m构造TreeMap,m可能有,也可能没有比较器
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) {
}
}

put操作:

    public V put(K key, V value) {
Entry<K,V> t = root;
//如果根节点为null
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 {//没有提供比较器,使用key的自然顺序,思想与上面一样
if (key == null)
throw new NullPointerException();
@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
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;
}

插入后调整

    private void fixAfterInsertion(Entry<K,V> x) {
x.color = RED;//节点颜色设置为红色
//循环条件x不为空,且不是根节点且父节点颜色是红色,如果不是红色,那就没有连续的红色节点,不需要调整,如果x是根节点,不需要调整,设置为黑色即可
while (x != null && x != root && x.parent.color == RED) {
//如果x的父节点是x的父节点的父节点的左节点
if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
//取x的父节点的父节点的右节点
Entry<K,V> y = rightOf(parentOf(parentOf(x)));
//如果y的颜色是红色
if (colorOf(y) == RED) {
//将x的父节点设置为黑色
setColor(parentOf(x), BLACK);
//将y的颜色设置为黑色
setColor(y, BLACK);
//将x的父结点的父节点设置为红色
setColor(parentOf(parentOf(x)), RED);
//x的父节点的父节点的性质可能被破坏,递归地处理这个过程
x = parentOf(parentOf(x));
} else {
//如果x是父节点的右节点
if (x == rightOf(parentOf(x))) {
x = parentOf(x);
//左旋
rotateLeft(x);
}
setColor(parentOf(x), BLACK);
setColor(parentOf(parentOf(x)), RED);
rotateRight(parentOf(parentOf(x)));
}
} else {//如果x的父节点是x父节点的父节点的右节点
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;//根节点始终为黑色
}

remove操作

    public V remove(Object key) {
//找出指定key的节点
Entry<K,V> p = getEntry(key);
if (p == null)
return null; V oldValue = p.value;
deleteEntry(p);//删除节点
return oldValue;//返回被删除节点的值
} 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;
}
}
}

get操作

    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();
@SuppressWarnings("unchecked")
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;//找不到,返回null
} //寻找的思想是一样的,只是比较的时候用比较器
final Entry<K,V> getEntryUsingComparator(Object key) {
@SuppressWarnings("unchecked")
K k = (K) key;
Comparator<? super K> cpr = comparator;
if (cpr != null) {
Entry<K,V> p = root;
while (p != null) {
int cmp = cpr.compare(k, p.key);
if (cmp < 0)
p = p.left;
else if (cmp > 0)
p = p.right;
else
return p;
}
}
return null;
}

红黑数满足的5个性质:

性质 1:每个节点要么是红色,要么是黑色。

性质 2:根节点永远是黑色的。

性质 3:所有的叶节点都是空节点(即 null),并且是黑色的。

性质 4:每个红色节点的两个子节点都是黑色。(从每个叶子到根的路径上不会有两个连续的红色节点)

性质 5:从任一节点到其子树中每个叶子节点的路径都包含相同数量的黑色节点。

插入或删除节点之后调整的目的都是为了满足上面的5个性质。

java.util.TreeMap源码分析的更多相关文章

  1. 结合java.util.TreeMap源码理解红黑树

    前言 本篇将结合JDK1.6的TreeMap源码,来一起探索红-黑树的奥秘.红黑树是解决二叉搜索树的非平衡问题. 当插入(或者删除)一个新节点时,为了使树保持平衡,必须遵循一定的规则,这个规则就是红- ...

  2. java.util.Collection源码分析和深度讲解

    写在开头 java.util.Collection 作为Java开发最常用的接口之一,我们经常使用,今天我带大家一起研究一下Collection接口,希望对大家以后的编程以及系统设计能有所帮助,本文所 ...

  3. java.util.HashMap源码分析

    在java jdk8中对HashMap的源码进行了优化,在jdk7中,HashMap处理“碰撞”的时候,都是采用链表来存储,当碰撞的结点很多时,查询时间是O(n). 在jdk8中,HashMap处理“ ...

  4. java.util.AbstractStringBuilder源码分析

    AbstractStringBuilder是一个抽象类,是StringBuilder和StringBuffer的父类,分析它的源码对StringBuilder和StringBuffer代码的理解有很大 ...

  5. java.util.Hashtable源码分析

    Hashtable实现一个键值映射的表.任何非null的object可以用作key和value. 为了能存取对象,放在表里的对象必须实现hashCode和equals方法. 一个Hashtable有两 ...

  6. java.util.Dictionary源码分析

    Dictionary是一个抽象类,Hashtable是它的一个子类. 类的声明:/** The <code>Dictionary</code> class is the abs ...

  7. java.util.TreeSet源码分析

    TreeSet是基于TreeMap实现的,元素的顺序取决于元素自身的自然顺序或者在构造时提供的比较器. 对于add,remove,contains操作,保证log(n)的时间复杂度. 因为Set接口的 ...

  8. java.util.Map源码分析

    /** * An object that maps keys to values. A map cannot contain duplicate keys; * each key can map to ...

  9. java.util.LinkedList源码分析

    public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, D ...

随机推荐

  1. IPC——匿名管道

    Linux进程间通信——使用匿名管道 在前面,介绍了一种进程间的通信方式:使用信号,我们创建通知事件,并通过它引起响应,但传递的信息只是一个信号值.这里将介绍另一种进程间通信的方式——匿名管道,通过它 ...

  2. 字典树(Trie)的java实现

    一.定义 字典树又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种.典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计.它的优点是:利用 ...

  3. Design Mode 之 结构模式

    这里我们主要介绍7种结构型模式:适配器模式.装饰模式.代理模式.外观模式.桥接模式.组合模式.享元模式.其中对象的适配器模式是各种模式的起源,我们看下面的图: B1.适配器模式(Adapter) 模式 ...

  4. 【¥200代金券、iPad等您来拿】 阿里云9大产品免费公测#10月9日-11月6日#

    #10.09-11.06#200元代金券.iPad大奖, 9大产品评测活动! 亲爱的阿里云小伙伴们: 云产品的多样性(更多的云产品)也是让用户深度使用云计算的关键.今年阿里云产品线越来越丰富,小云搜罗 ...

  5. 【Shell脚本学习7】Shell脚本学习指南分享

    http://yunpan.cn/cyARvNiaiLhfR (提取码:2878)

  6. setcookie 之 我见

    $default_currency=get_default_currency(); $_COOKIE['currency'] = $default_currency['currency']; $_CO ...

  7. [课程相关]homework-09

    零.前言 这次的作业比较特殊,有两种做法.由于我对网页很熟悉,所以选择网页. 细节不赘述,下面写一下这次作业的几个亮点. 一.亮点 最大的亮点就是这个页面是纯客户端的,没有服务端.也就是说所有功能都是 ...

  8. 在Firefox中通过AJAX跨域访问Web资源---

    一.解决在firefox中无法跨域访问的问题 AJAX从本质上讲就是命名用XMLHttpRequest组件来向服务端发送HTTP请求,请接收相应信息.至于成功接收到响应信息后的操作,就和普通的Web客 ...

  9. 强大的矢量图形库:Raphael JS 中文帮助文档及教程

    Raphael 是一个用于在网页中绘制矢量图形的 Javascript 库.它使用 SVG W3C 推荐标准和 VML 作为创建图形的基础,你可以通过 JavaScript 操作 DOM 来轻松创建出 ...

  10. Ubuntu15.10使用mysql

    安装 sudo apt-get install mysql-server sudo apt-get install mysql-client sudo apt-get install libmysql ...