目录
简介
字段 comparator,root,size,modCount
Entry类
构造器4个
查询方法 size,containsKey,containsValue,get,comparator,firstKey,lastKey
查询的辅助方法 8个getXXXEntry和getEntryXXX ,successor,predecessor
put方法
/**
* 一个基于红黑树的NavigableMap实现。
* 映射根据其键的自然顺序进行排序,或者根据使用的构造函数由创建映射时提供的比较器进行排序。
* 注意:hashmap支持null的key和value。
* treemap put时,如果指定key是null,并且map使用自然排序。或者它的comparator不允许null的key,会抛出NullPointerException。
* treemap允许null的value。
*
* 这个实现为containsKey、get、put和remove操作提供了保证的log(n)时间成本。
* 算法是对Cormen, Leiserson和Rivest介绍的算法的改编。
*
*
请注意,如果要正确地实现map接口,树映射(与任何已排序的映射一样)维护的顺序,以及是否提供显式比较器,都必须与equals一致。
* (参见Comparable或Comparator获得与equals一致的精确定义。)
* 这是因为Map接口是根据equals操作定义的,但是一个排序后的Map使用它的compareTo(或compare)方法执行所有的键比较,
* 所以从排序后的Map的角度来看,这个方法认为相等的两个键是相等的。
* 排序后的映射的行为定义良好,即使它的排序与等于不一致;它只是没有遵守地图接口的通用契约。
*
*
注意,这个实现不是同步的。如果多个线程同时访问一个映射,并且至少有一个线程在结构上修改了映射,那么它必须在外部同步。
* (结构修改是指增加或删除一个或多个映射的操作;仅更改与现有键关联的值不是结构修改)。
* 这通常是通过对一些自然封装了映射的对象进行同步来实现的。
* 如果不存在这样的对象,则应该使用Collections.synchronizedSortedMap方法。
* 这最好在创建时完成,以防止意外的不同步访问地图:
*
* SortedMap m = Collections.synchronizedSortedMap(new TreeMap(...));
*
* 这个类返回的集合视图方法,返回的Iterator是快速失败:
* 如果Iterator创建后,map结构上被修改,任何时候以任何方式,除非通过迭代器的删除方法,迭代器将抛出ConcurrentModificationException。
* 因此,在面对并发修改时,迭代器会快速而干净地失败,而不是在将来某个不确定的时间冒任意的、不确定的行为的风险。
*
*
注意,不能保证迭代器的快速故障行为,因为通常来说,在存在非同步并发修改的情况下,不可能做出任何严格的保证。
* 故障快速迭代器在最大努力的基础上抛出ConcurrentModificationException。
* 因此,编写一个依赖于这个异常的正确性的程序是错误的:迭代器的快速故障行为应该只用于检测bug。
*
*
这个类和他的视图,的方法,返回的Map.Entry对,表示它们被生成时的映射快照。
* 他们不支持进入Entry.setValue方法。(但是请注意,可以使用put更改关联映射中的映射。)
*
* @param the type of keys maintained by this map
* @param the type of mapped values
*
* @author Josh Bloch and Doug Lea
* @see Map
* @see HashMap
* @see Hashtable
* @see Comparable
* @see Comparator
* @see Collection
* @since 1.2
*/
public class TreeMap
extends AbstractMap
implements NavigableMap, Cloneable, java.io.Serializable
/**
* 比较器用于维护树映射中的顺序,如果使用键的自然顺序,则为null。
*
* @serial
*/
private final Comparator super K> comparator;
// 红黑树的root
private transient Entry root;
/**
* 树中entry对的数量
*/
private transient int size = 0;
/**
* 对树的结构修改的次数。
*/
private transient int modCount = 0;
/**
* 树中的节点。也作为将键-值对传递回用户的工具(参见Map.Entry)。
*/
static final class Entry implements Map.Entry {
// 不是final的key和value
K key;
V value;
// 左孩子,右孩子,父节点
Entry left;
Entry right;
Entry parent;
// 默认颜色是黑色
boolean color = BLACK;
/**
* 使用给定的键、值和父元素创建一个新节点,并使用空子链接和黑色。
*/
Entry(K key, V value, Entry 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;
// 比较key和value
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());
// key的hashcode与value的hashcode异或
return keyHash ^ valueHash;
}
public String toString() {
return key + "=" + value;
}
}
/**
* 使用键的自然顺序构造一个新的空树映射。
* 插入到映射中的所有键必须实现可比接口。
* 而且,所有这些键必须是相互可比的:k1. compareto (k2)不能让map中的任何键k1和k2抛出ClassCastException。
* 如果用户试图将一个键放入违反此约束的映射中
* (例如,用户试图将一个字符串键放入一个键为整数的映射中),那么put(对象键、对象值)调用将抛出一个ClassCastException。
*/
public TreeMap() {
comparator = null;
}
/**
* 构造一个新的空树映射,按照给定的比较器排序。
* 所有插入到映射中的键必须是可相互比较的,通过给定的比较器:comparator.compare(k1, k2)不能为映射中的任何键k1和k2抛出ClassCastException。
* 如果用户试图将键放入违反此约束的映射中,则put(对象键、对象值)调用将抛出ClassCastException。
*
* @param comparator the comparator that will be used to order this map.
* If {@code null}, the {@linkplain Comparable natural
* ordering} of the keys will be used.
*/
public TreeMap(Comparator super K> comparator) {
this.comparator = comparator;
}
/**
* 构造一个新的树映射,其中包含与给定映射相同的映射,按照键的自然顺序排序。
* 插入到新映射中的所有键必须实现Comparable接口。
* 而且,所有这些键必须是相互可比的:k1. compareto (k2)不能为map中的任何键k1和k2抛出ClassCastException。
* 此方法在n*log(n)时间内运行。
*
* @param m the map whose mappings are to be placed in this map
* @throws ClassCastException if the keys in m are not {@link Comparable},
* or are not mutually comparable
* @throws NullPointerException if the specified map is null
*/
public TreeMap(Map extends K, ? extends V> m) {
comparator = null;
putAll(m);
}
/**
* 构造一个包含相同映射的新树映射,并使用与指定SortedMap相同的顺序。
* 这种方法在线性时间内运行。
*
* @param m the sorted map whose mappings are to be placed in this map,
* and whose comparator is to be used to sort this map
* @throws NullPointerException if the specified map is null
*/
public TreeMap(SortedMap m) {
// comparator为m的comparator
comparator = m.comparator();
try {
buildFromSorted(m.size(), m.entrySet().iterator(), null, null);
} catch (java.io.IOException cannotHappen) {
} catch (ClassNotFoundException cannotHappen) {
}
}
// Query Operations
/**
* 返回此映射中的键值映射的数目。
*
* @return the number of key-value mappings in this map
*/
public int size() {
return size;
}
/**
* 如果此映射包含指定键的映射,则返回true。
*
* @param key key whose presence in this map is to be tested
* @return {@code true} if this map contains a mapping for the
* specified key
* @throws ClassCastException if the specified key cannot be compared
* with the keys currently in the map
* @throws NullPointerException if the specified key is null
* and this map uses natural ordering, or its comparator
* does not permit null keys
*/
public boolean containsKey(Object key) {
return getEntry(key) != null;
}
/**
* 如果此映射将一个或多个键映射到指定的值,则返回true。
* 更正式地说,当且仅当此映射包含至少一个到值v的映射(value==null ?v = = null: value.equals (v))。
* 对于大多数实现,此操作可能需要映射大小的时间线性。
*
* @param value value whose presence in this map is to be tested
* @return {@code true} if a mapping to {@code value} exists;
* {@code false} otherwise
* @since 1.2
*/
public boolean containsValue(Object value) {
// 从第一个entry开始,不断e = successor(e))循环
for (Entry e = getFirstEntry(); e != null; e = successor(e))
if (valEquals(value, e.value))
return true;
return false;
}
/**
* 返回指定键映射到的值,如果该映射不包含键的映射,则返回null。
*
* 更正式地说,如果这个映射包含一个从键k到值v的映射,
* 使得键根据映射的顺序与k进行比较,两者相同,那么这个方法将返回v;否则返回null。
* (最多可以有一个这样的映射。)
*
*
返回值为null并不一定表示映射不包含键的映射;映射也可有value为null。
* containsKey操作可以用来区分这两种情况。
*
* @throws ClassCastException if the specified key cannot be compared
* with the keys currently in the map
* @throws NullPointerException if the specified key is null
* and this map uses natural ordering, or its comparator
* does not permit null keys
*/
public V get(Object key) {
// 根据getEntry方法
Entry p = getEntry(key);
return (p==null ? null : p.value);
}
public Comparator super K> comparator() {
return comparator;
}
/**
* @throws NoSuchElementException {@inheritDoc}
*/
public K firstKey() {
return key(getFirstEntry());
}
/**
* @throws NoSuchElementException {@inheritDoc}
*/
public K lastKey() {
return key(getLastEntry());
}
/**
* 返回给定键的entry,如果映射不包含键的entry,则返回null。
*
* @return this map's entry for the given key, or {@code null} if the map
* does not contain an entry for the key
* @throws ClassCastException if the specified key cannot be compared
* with the keys currently in the map
* @throws NullPointerException if the specified key is null
* and this map uses natural ordering, or its comparator
* does not permit null keys
*/
final Entry getEntry(Object key) {
// 为了性能考虑,卸载基于比较器的版本
if (comparator != null)
return getEntryUsingComparator(key);
// key不能为null
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
// key变为comparable类型
Comparable super K> k = (Comparable super K>) key;
Entry p = root;
while (p != null) {
int cmp = k.compareTo(p.key);
// 小于0,p为左孩子,大于0,p为右孩子
if (cmp < 0)
p = p.left;
else if (cmp > 0)
p = p.right;
else
// 如果比较结果为0,则返回当前节点
return p;
}
return null;
}
/**
* 使用比较器的getEntry版本。从getEntry中分离出来。
* (对于不太依赖比较器性能的大多数方法来说,这样做是不值得的,但是在这里是值得的。)
*/
final Entry getEntryUsingComparator(Object key) {
@SuppressWarnings("unchecked")
K k = (K) key;
Comparator super K> cpr = comparator;
if (cpr != null) {
Entry p = root;
while (p != null) {
// 使用treemap里面的comparator进行比较,其余相同
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;
}
/**
* 获取与指定键对应的项;如果不存在这样的项,则返回大于指定键的最小键的项;
* 如果不存在这样的条目(即,则树中最大的键值小于指定的键值),返回null。
*/
final Entry getCeilingEntry(K key) {
Entry p = root;
while (p != null) {
int cmp = compare(key, p.key);
if (cmp < 0) {
// key小于p,p大于key
if (p.left != null)
p = p.left;
else
// 如果没有左孩子,代表p是刚刚大于key的节点
return p;
} else if (cmp > 0) {
// key大于p,p小于key
if (p.right != null) {
p = p.right;
} else {
// 如果没有右孩子,p是刚刚小于key的节点,找到比p稍微大点的节点
// 6
// 4 8
// 2 5 7 9
// 如果p是2,返回4,如果p是5,返回6
// 即返回p的第一个左孩子是,p的祖先节点(包括p),的祖先,
Entry parent = p.parent;
Entry ch = p;
while (parent != null && ch == parent.right) {
ch = parent;
parent = parent.parent;
}
return parent;
}
} else
// 如果相同,返回该节点
return p;
}
return null;
}
/**
* 获取与指定键对应的项;
* 如果不存在这样的项,则返回小于指定键的最大键的项;
* 如果不存在这样的条目,则返回null。
*/
final Entry getFloorEntry(K key) {
Entry p = root;
while (p != null) {
int cmp = compare(key, p.key);
if (cmp > 0) {
if (p.right != null)
p = p.right;
else
return p;
} else if (cmp < 0) {
if (p.left != null) {
p = p.left;
} else {
// 如果没有左孩子,p是刚刚大于key的节点,key小于p,找到比p稍微小于点的节点
// 6
// 4 8
// 2 5 7 9
// 如果p是5,返回4,如果p是7,返回6
// 即返回p的第一个右孩子是,p的祖先节点(包括p),的祖先,
Entry parent = p.parent;
Entry ch = p;
while (parent != null && ch == parent.left) {
ch = parent;
parent = parent.parent;
}
return parent;
}
} else
return p;
}
return null;
}
/**
* 获取大于指定键的最小键的项;
* 如果不存在这样的项,则返回大于指定键的最小键的项;
* 如果不存在这样的条目,则返回null。
*/
final Entry getHigherEntry(K key) {
Entry p = root;
while (p != null) {
int cmp = compare(key, p.key);
if (cmp < 0) {
if (p.left != null)
p = p.left;
else
return p;
} else {
if (p.right != null) {
p = p.right;
} else {
Entry parent = p.parent;
Entry ch = p;
while (parent != null && ch == parent.right) {
ch = parent;
parent = parent.parent;
}
return parent;
}
}
}
return null;
}
/**
* 返回小于指定键的最大键的项;
* 如果不存在这样的条目(即,则树中最小的键值大于指定的键值),返回null。
*/
final Entry getLowerEntry(K key) {
Entry p = root;
while (p != null) {
int cmp = compare(key, p.key);
if (cmp > 0) {
if (p.right != null)
p = p.right;
else
return p;
} else {
if (p.left != null) {
p = p.left;
} else {
Entry parent = p.parent;
Entry ch = p;
while (parent != null && ch == parent.left) {
ch = parent;
parent = parent.parent;
}
return parent;
}
}
}
return null;
}
/**
* 返回TreeMap中的第一个条目(根据TreeMap的键排序函数)。如果树形图为空,则返回null。
*/
final Entry getFirstEntry() {
Entry p = root;
if (p != null)
// 找到最左节点
while (p.left != null)
p = p.left;
return p;
}
/**
* 返回TreeMap中的最后一个条目(根据TreeMap的键排序函数)。如果树形图为空,则返回null。
*/
final Entry getLastEntry() {
Entry p = root;
if (p != null)
while (p.right != null)
p = p.right;
return p;
}
/**
* 返回指定项的继承项,如果没有继承项,则返回null。(即刚刚大于t的entry)
*/
static TreeMap.Entry successor(Entry t) {
if (t == null)
return null;
else if (t.right != null) {
// 如果有右孩子,则返回右孩子的最最左孩子
Entry p = t.right;
while (p.left != null)
p = p.left;
return p;
} else {
// 如果没有右孩子
// 6
// 4 8
// 2 5 7 9
// 如果p是2,返回4,如果p是5,返回6
// 即返回p的第一个左孩子是,p的祖先节点(包括p),的祖先,
Entry p = t.parent;
Entry ch = t;
while (p != null && ch == p.right) {
ch = p;
p = p.parent;
}
return p;
}
}
/**
* 返回指定项的前任,如果没有,则返回null。
*/
static Entry predecessor(Entry t) {
if (t == null)
return null;
else if (t.left != null) {
Entry p = t.left;
while (p.right != null)
p = p.right;
return p;
} else {
Entry p = t.parent;
Entry ch = t;
while (p != null && ch == p.left) {
ch = p;
p = p.parent;
}
return p;
}
}
/**
* 将指定值与此映射中的指定键关联。
* 如果映射之前包含键的映射,则替换旧值。
* 如果指定key是null,并且map使用自然排序。或者它的comparator不允许null的key,会抛出NullPointerException。
*
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
*
* @return the previous value associated with {@code key}, or
* {@code null} if there was no mapping for {@code key}.
* (A {@code null} return can also indicate that the map
* previously associated {@code null} with {@code key}.)
* @throws ClassCastException if the specified key cannot be compared
* with the keys currently in the map
* @throws NullPointerException 如果指定key是null,并且map使用自然排序。或者它的comparator不允许null的key。
*/
public V put(K key, V value) {
Entry t = root;
if (t == null) {
compare(key, key); // type (and possibly null) check 类型(和可能为null)的检查
// 初始化root节点
root = new Entry<>(key, value, null);
size = 1;
modCount++;
return null;
}
int cmp;
Entry parent;
// comparator和comparable的情况分开来
Comparator super K> cpr = comparator;
if (cpr != null) {
do {
// 每次记录下parent,然后t跑到孩子处
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);
// 如果没找到,t到了应该到的孩子处,为null,parent为t的父节点
} while (t != null);
}
else {
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);
}
// 没有找到节点,在parent处增加孩子
Entry e = new Entry<>(key, value, parent);
if (cmp < 0)
parent.left = e;
else
parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
return null;
}