系列文章:
- Java集合系列01之概览
- Java集合系列02之ArrayList源码分析
- Java集合系列03之LinkedList源码分析
- Java集合系列04之fail-fast机制分析
- Java集合系列05之Vector&Stack源码分析及List总结
- Java集合系列06之Map接口概览
- Java集合系列07之HashMap源码分析
- Java集合系列08之WeakHashMap源码分析
- Java集合系列09之TreeMap源码分析
- Java集合系列10之Hashtable源码分析
前言
TreeMap是基于红黑树实现的有序键值对集合,排序方法取决于给定的构造函数,其系列操作方法如remove,get,put等的时间复杂度都是O(logn),TreeMap也是非线程安全的,其定义如下:
public class TreeMap
extends AbstractMap
implements NavigableMap, Cloneable, java.io.Serializable
可以看到TreeMap继承自AbstractMap,实现了NavigableMap接口,支持一系列的导航方法,如返回满足条件的有序键值对集合。
红黑树是平衡的二叉排序树,定义具有五条性质,关于红黑树的原理及插入,删除操作,可以见面试旧敌之红黑树(直白介绍深入理解)。
继承关系
TreeMap继承关系
java.lang.Object
|___ java.util.AbstractMap
|___ java.util.TreeMap
所有已实现的接口:
Serializable, Cloneable, Map, NavigableMap, SortedMap
关系图
- TreeMap的本质是红黑树,root是红黑树的根节点
- comparator用来比较key的大小
- size是红黑树节点的个数
构造函数
// 默认构造函数,使用该构造函数,则TreeMap按自然排序排列
public TreeMap()
// 带指定比较器的构造函数
public TreeMap(Comparator super K> comparator)
// 创建的TreeMap包含Map
public TreeMap(Map extends K, ? extends V> m)
// 创建的TreeMap包含SortedMap
public TreeMap(SortedMap m)
API
Entry ceilingEntry(K key)
K ceilingKey(K key)
void clear()
Object clone()
Comparator super K> comparator()
boolean containsKey(Object key)
NavigableSet descendingKeySet()
NavigableMap descendingMap()
Set> entrySet()
Map.Entry firstEntry()
K firstKey()
Map.Entry floorEntry(K key)
K floorKey(K key)
V get(Object key)
NavigableMap headMap(K tokey, boolean inclusive)
SortedMap headMap(K tokey)
Map.Entry higherEntry(K key)
K higherKey(K key)
boolean isEmpty()
Set keySet()
Map.Entry lastEntry()
K lastKey()
Map.Entry lowerEntry(K key)
K lowerKey(K key)
NavigableSet navigableKeySet()
Map.Entry pollFirstEntry()
Map.Entry pollLastEntry()
V put(K key, V value)
V remove(Object key)
int size()
SortedMap subMap(K fromInclusive, K toExclusive)
NavigableMap subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive)
NavigableMap tailMap(K fromKey, boolean inclusive)
SortedMap tailMap(K fromKey)
源码分析
成员变量
// 比较器,用来排序
private final Comparator super K> comparator;
// 根节点
private transient Entry root;
// 红黑树节点总数
private transient int size = 0;
// 修改次数
private transient int modCount = 0;
构造函数
// 默认构造函数,排序方式用自然排序
public TreeMap() {
comparator = null;
}
// 带比较器的默认构造函数
public TreeMap(Comparator super K> comparator) {
this.comparator = comparator;
}
// 带Map的构造函数
public TreeMap(Map extends K, ? extends V> m) {
comparator = null;
putAll(m);
}
// 带SortedMap的构造函数
public TreeMap(SortedMap m) {
comparator = m.comparator();
try {
buildFromSorted(m.size(), m.entrySet().iterator(), null, null);
} catch (java.io.IOException cannotHappen) {
} catch (ClassNotFoundException cannotHappen) {
}
}
buildFromSorted
// 由已排好序的map新建TreeMap
private void buildFromSorted(int size, Iterator it,
java.io.ObjectInputStream str,
V defaultVal)
throws java.io.IOException, ClassNotFoundException {
this.size = size;
root = buildFromSorted(0, 0, size-1, computeRedLevel(size),
it, str, defaultVal);
}
// 由已排好序的map新建TreeMap
// 将map中的元素逐个添加到TreeMap中,并返回map的中间元素作为根节点。
private final Entry buildFromSorted(int level, int lo, int hi,
int redLevel,
Iterator it,
java.io.ObjectInputStream str,
V defaultVal)
throws java.io.IOException, ClassNotFoundException {
// 如果high > low 则直接返回
if (hi < lo) return null;
// 获取中间元素
int mid = (lo + hi) / 2;
Entry left = null;
// 若lo小于mid,则递归调用获取(middle的)左孩子。
if (lo < mid)
left = buildFromSorted(level+1, lo, mid - 1, redLevel,
it, str, defaultVal);
// 获取middle节点对应的key和value
K key;
V value;
if (it != null) {
if (defaultVal==null) {
Map.Entry entry = (Map.Entry)it.next();
key = entry.getKey();
value = entry.getValue();
} else {
key = (K)it.next();
value = defaultVal;
}
} else {
key = (K) str.readObject();
value = (defaultVal != null ? defaultVal : (V) str.readObject());
}
// 创建middle节点
Entry middle = new Entry(key, value, null);
// 若当前节点的深度=红色节点的深度,则将节点着色为红色。
if (level == redLevel)
middle.color = RED;
// 设置middle为left的父亲,left为middle的左孩子
if (left != null) {
middle.left = left;
left.parent = middle;
}
if (mid < hi) {
// 递归调用获取(middle的)右孩子。
Entry right = buildFromSorted(level+1, mid+1, hi, redLevel,
it, str, defaultVal);
// 设置middle为left的父亲,left为middle的左孩子
middle.right = right;
right.parent = middle;
}
return middle;
}
增加元素
// 将键值对加入TreeMap中
public V put(K key, V value) {
Entry 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 parent;
Comparator super K> cpr = comparator;
// 在红黑树中找到键值对插入的位置
// 以key来排序,因此比较key即可
// comparator不为null
if (cpr != null) {
do {
parent = t;
// 比较当前节点key和待插入key间关系
cmp = cpr.compare(key, t.key);
// cmp小于0,则插入t节点的左子树中
if (cmp < 0)
t = t.left;
// cmp大于0,则插入t节点的右子树中
else if (cmp > 0)
t = t.right;
// cmp等于0,说明红黑树中已有该key,则重设value
else
return t.setValue(value);
} while (t != null);
}
// 如果comparator为null,则用自然排序方式比较key
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);
}
// 新建待插入的红黑树节点,并返回节点值
Entry e = new Entry<>(key, value, parent);
if (cmp < 0)
parent.left = e;
else
parent.right = e;
// 维护红黑树的特性
fixAfterInsertion(e);
size++;
modCount++;
return null;
}
// 将map中全部节点加入TreeMap中
public void putAll(Map extends K, ? extends V> map) {
// map大小
int mapSize = map.size();
// 如果TreeMap的大小是0,且map的大小不是0,且map属于SortMap类型
if (size==0 && mapSize!=0 && map instanceof SortedMap) {
// 判断map的comparator与当前comparator是否相等
// 如果相等则将map中所有元素加入TreeMap中
Comparator> c = ((SortedMap,?>)map).comparator();
if (c == comparator || (c != null && c.equals(comparator))) {
++modCount;
try {
buildFromSorted(mapSize, map.entrySet().iterator(),
null, null);
} catch (java.io.IOException cannotHappen) {
} catch (ClassNotFoundException cannotHappen) {
}
return;
}
}
// 否则调用AbstractMap中的putAll方法
// AbstractMap中的putAll方法又会调用TreeMap的put方法
super.putAll(map);
}
获取元素
// 获取key对应的value值
public V get(Object key) {
// 获取key对应的节点p
Entry p = getEntry(key);
return (p==null ? null : p.value);
}
// 获取TreeMap中key对应的节点
final Entry getEntry(Object key) {
// 如果comparator不为null,则调用getEntryUsingComparator()来获取节点
if (comparator != null)
return getEntryUsingComparator(key);
if (key == null)
throw new NullPointerException();
// comparator为null,则用自然排序的方式来查找比较
@SuppressWarnings("unchecked")
Comparable super K> k = (Comparable super K>) key;
Entry p = root;
while (p != null) {
int cmp = k.compareTo(p.key);
// cmp小于0,则继续遍历p节点左子树
if (cmp < 0)
p = p.left;
// cmp大于0,则继续遍历p节点右子树
else if (cmp > 0)
p = p.right;
// cmp等于0,则返回p节点
else
return p;
}
return null;
}
// 获取TreeMap中key对应的节点(comparator不为null时)
final Entry getEntryUsingComparator(Object key) {
@SuppressWarnings("unchecked")
K k = (K) key;
// comparator不为null,则用comparator方式来比较
Comparator super K> cpr = comparator;
if (cpr != null) {
Entry p = root;
while (p != null) {
int cmp = cpr.compare(k, p.key);
// cmp小于0,则继续遍历p节点左子树
if (cmp < 0)
p = p.left;
// cmp大于0,则继续遍历p节点右子树
else if (cmp > 0)
p = p.right;
// cmp等于0,则返回p节点
else
return p;
}
}
return null;
}
删除元素
// 删除TreeMap中的键为key的节点,并返回节点值
public V remove(Object key) {
// 先获取键为key的节点
Entry p = getEntry(key);
// 节点为null,则返回null
if (p == null)
return null;
V oldValue = p.value;
// 删除节点
deleteEntry(p);
return oldValue;
}
导航方法
返回不小于key的最小节点
// 返回不小于key的最小键值对,没有则返回null
public Map.Entry ceilingEntry(K key) {
return exportEntry(getCeilingEntry(key));
}
// 返回不小于key的最小键值对对应的key,没有则返回null
public K ceilingKey(K key) {
return keyOrNull(getCeilingEntry(key));
}
// 获取TreeMap中不小于key的最小节点,不存在则返回null
final Entry getCeilingEntry(K key) {
// p为根节点
Entry p = root;
while (p != null) {
int cmp = compare(key, p.key);
// 若key < p.key且p存在左子树,则让p为p的左子树
// p不存在左子树就返回p
if (cmp < 0) {
if (p.left != null)
p = p.left;
else
return p;
} else if (cmp > 0) {
// 若key > p.key且p存在右子树,则让p为p的右子树
if (p.right != null) {
p = p.right;
} else {
// 若p不存在右子树,则找出p的后继节点
// p的后继节点有两种可能,一种是null,另一种是TreeMap中大于key的最小节点
Entry parent = p.parent;
Entry ch = p;
// 如果p是p的parent的左孩子,则直接返回p.parent
// 如果p是p的parent的右孩子,则一直向上寻找parent,直到parent为null
while (parent != null && ch == parent.right) {
ch = parent;
parent = parent.parent;
}
return parent;
}
// 如果key == p.key则返回p
} else
return p;
}
return null;
}
// 新建一个AbstractMap.SimpleImmutableEntry类型对象,并返回
// SimpleImmutableEntry实际上是简化的key-value节点
static Map.Entry exportEntry(TreeMap.Entry e) {
return (e == null) ? null :
new AbstractMap.SimpleImmutableEntry<>(e);
}
返回不大于key的最大节点
// 返回不大于key的最大键值对,没有则返回null
public Map.Entry floorEntry(K key) {
return exportEntry(getFloorEntry(key));
}
// 返回不大于key的最大的键值的KEY,没有则返回null
public K floorKey(K key) {
return keyOrNull(getFloorEntry(key));
}
// 获取TreeMap中不大于key的最小节点,不存在则返回null
// getFloorEntry和getCeilingEntry的原理类似,参照其理解
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 {
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;
}
返回大于key的最小的节点
// 返回大于key的最小键值对,没有则返回null
public Map.Entry higherEntry(K key) {
return exportEntry(getHigherEntry(key));
}
// 返回大于key的最小键值对的KEY,没有则返回null
public K higherKey(K key) {
return keyOrNull(getHigherEntry(key));
}
// 获取TreeMap中大于key的最小节点,不存在则返回null
// getHigherEntry和getCeilingEntry仅在于不返回key相等的键值对
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;
}
返回小于key的最大节点
// 返回小于key的最大的键值对,没有则返回null
public Map.Entry lowerEntry(K key) {
return exportEntry(getLowerEntry(key));
}
// 返回小于key的最大的键值对所对应的KEY,没有则返回null
public K lowerKey(K key) {
return keyOrNull(getLowerEntry(key));
}
// 获取TreeMap中小于key的最大节点,不存在则返回null
// getLowerEntry和getFloorEntry仅在于不返回key相等的键值对
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;
}
数据结构
static final class Entry implements Map.Entry {
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;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
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());
}
// 覆盖hashCode
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;
}
}
遍历
假设key和value
都是String
型
- 根据
entrySet()
通过Iterator
遍历
Iterator iter = map.entrySet().iterator();
while(iter.hasNext()){
Map.Entry entry = (Map.Entry)iter.next();
key = (String)entry.getKey();
value = (String)entry.getValue();
}
- 根据
keySet()
通过Iterator
遍历
Iterator iter = map.keySet().iterator();
while(iter.hasNext()){
key = (String)iter.next();
value = (String)map.get(key);
}
- 根据
value()
通过Iterator
遍历
Iterator iter = map.values().iterator();
while(iter.hasNext()){
value = (String)iter.next;
}
参考信息
- Java 集合系列12之 TreeMap详细介绍(源码解析)和使用示例
- 红黑树(一)之 原理和算法详细介绍