疑问:TreeMap的clear()方法与LinkedList,ArrayList,HashMapd等的比较
一、定义
public class TreeMap<K,V>
extends AbstractMap<K,V>
implements NavigableMap<K,V>, Cloneable, java.io.Serializable
TreeMap扩展自AbstractMap
实现NavigableMap
实现Cloneable,实现Serializable
来看下NavigableMap
public interface SortedMap<K,V> extends Map<K,V> {
Comparator<? super K> comparator();
//返回formKey到toKey(不包括)间的视图
SortedMap<K,V> subMap(K fromKey, K toKey);
//返回小于toKey的视图
SortedMap<K,V> headMap(K toKey);
//返回小于tailMap的视图
SortedMap<K,V> tailMap(K fromKey);
//返回first key
K firstKey();
//返回last key
K lastKey();
//返回key视图,与SortMap存在映射关系,修改set<K>或SortedMap中的一个,另一个也会改变
Set<K> keySet();
Collection<V> values();
Set<Map.Entry<K, V>> entrySet();
}
public interface NavigableMap<K,V> extends SortedMap<K,V> {
Map.Entry<K,V> lowerEntry(K key);
K lowerKey(K key);
Map.Entry<K,V> floorEntry(K key);
K floorKey(K key);
Map.Entry<K,V> ceilingEntry(K key);
K ceilingKey(K key);
Map.Entry<K,V> higherEntry(K key);
K higherKey(K key);
Map.Entry<K,V> firstEntry();
Map.Entry<K,V> lastEntry();
Map.Entry<K,V> pollFirstEntry();
Map.Entry<K,V> pollLastEntry();
//返回逆序视图
NavigableMap<K,V> descendingMap();
NavigableSet<K> navigableKeySet();
//逆序key视图
NavigableSet<K> descendingKeySet();
//根据formInclusive判断返图视图是否包含formKey
//根据toInclusive判断返图视图是否包含toKey
NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
K toKey, boolean toInclusive);
//根据toInclusive判断返图视图是否包含toKey
NavigableMap<K,V> headMap(K toKey, boolean inclusive);
NavigableMap<K,V> tailMap(K fromKey, boolean inclusive);
SortedMap<K,V> subMap(K fromKey, K toKey);
SortedMap<K,V> headMap(K toKey);
SortedMap<K,V> tailMap(K fromKey);
}
SortMap和SortedMap提供了一些排序需要基本方法。
二、底层
红黑树
恶补这块花费了很久时间。。
理解红黑树的时候有个坑,在这里记录一下:TreeMap中的红黑树叶节点都是空节点,都不存储数据,只要不是叶节点都会存储数据。
三、构造器及常量
//comparator比较器,为null时,按照自然顺序排序
private final Comparator<? super K> comparator;
//根root
private transient Entry<K,V> root = null;
//size
private transient int size = 0;
//多线程是舒勇
private transient int modCount = 0;
//空tree,自然顺序排序
public TreeMap() {
comparator = null;
}
//空tree,通过comparator来比较
public TreeMap(Comparator<? super K> comparator) {
this.comparator = comparator;
}
//tree中m包含entry,entrys按照自然排序重新进行排序,
//运行时间为 n*log(n)。
public TreeMap(Map<? extends K, ? extends V> m) {
comparator = null;
putAll(m);
}
//运行时间n
//生成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) {
}
}
//通过递归生成一个平衡二叉树
//生产二叉树的结构:最高层节点颜色都为red,其余black
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);
}
/*
* 通过递归获取从lo-hi见的节点树,返回树的跟
*/
private final Entry<K,V> buildFromSorted(int level, int lo, int hi,
int redLevel,
Iterator it,
java.io.ObjectInputStream str,
V defaultVal)
throws java.io.IOException, ClassNotFoundException {
/*
* Strategy: The root is the middlemost element. To get to it, we
* have to first recursively construct the entire left subtree,
* so as to grab all of its elements. We can then proceed with right
* subtree.
*
* The lo and hi arguments are the minimum and maximum
* indices to pull out of the iterator or stream for current subtree.
* They are not actually indexed, we just proceed sequentially,
* ensuring that items are extracted in corresponding order.
*/
if (hi < lo) return null;
//取得中间值
int mid = (lo + hi) >>> 1;
Entry<K,V> left = null;
//取得左子树
if (lo < mid)
left = buildFromSorted(level+1, lo, mid - 1, redLevel,
it, str, defaultVal);
// extract key and/or value from iterator or stream
K key;
V value;
if (it != null) {//存在迭代器,通过迭代器录入数据
if (defaultVal==null) {
//val为空,说明it类型为Entry,通过Entry获得value值
Map.Entry<K,V> entry = (Map.Entry<K,V>)it.next();
key = entry.getKey();
value = entry.getValue();
} else {
//val不为空,value直接赋值
key = (K)it.next();
value = defaultVal;
}
} else { //通过流取值
key = (K) str.readObject();
value = (defaultVal != null ? defaultVal : (V) str.readObject());
}
Entry<K,V> middle = new Entry<>(key, value, null);
// level == redLevel ,则此时的结点为红色
if (level == redLevel)
middle.color = RED;
if (left != null) {
middle.left = left;
left.parent = middle;
}
if (mid < hi) {
//获取右节点
Entry<K,V> right = buildFromSorted(level+1, mid+1, hi, redLevel,
it, str, defaultVal);
middle.right = right;
right.parent = middle;
}
return middle;
}
//获取叶子节点的层数
private static int computeRedLevel(int sz) {
int level = 0;
for (int m = sz - 1; m >= 0; m = m / 2 - 1)
level++;
return level;
}
三、put,get、remove
public V get(Object key) {
Entry<K,V> p = getEntry(key);
return (p==null ? null : p.value);
}
final Entry<K,V> getEntry(Object key) {
// 按自然顺序排序时,调用getEntryUsingComparator,两者的性能并没有差异
if (comparator != null)
return getEntryUsingComparator(key);
if (key == null)
throw new NullPointerException();
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;
public void putAll(Map<? extends K, ? extends V> map) {
int mapSize = map.size();
if (size==0 && mapSize!=0 && map instanceof SortedMap) {
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;
}
}
super.putAll(map);
}
//do-wile的典型用法哦
public V put(K key, V value) {
Entry<K,V> t = root;
//第一种情况,tree为空
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-while,因为上面已经比较t==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);
//将e插入到tree中,然后进行调整
if (cmp < 0)
parent.left = e;
else
parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
return null;
}
/**
* 求t的下一个节点,
*/
static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) {
if (t == null)
return null;
//当t有右子节点时,t的下一个节点在以t.right为根的树中
else if (t.right != null) {
Entry<K,V> p = t.right;
while (p.left != null)
p = p.left;
return p;
//t没有右子节点,t的下一个节点在为t的父辈节点中
} else {
Entry<K,V> p = t.parent;
Entry<K,V> ch = t;
//parent = null,遍历完成,没有next值
//p.parent.right = p 时,说明t.parent < p,需要继续向上遍历
while (p != null && ch == p.right) {
ch = p;
p = p.parent;
}
return p;
}
}
private void rotateLeft(Entry<K,V> p) {
if (p != null) {
Entry<K,V> r = p.right;
//右节点指向右节点。left
p.right = r.left;
if (r.left != null)
//右节点。left.parent指向p
r.left.parent = p;
//右节点。parent指向p,parent
r.parent = p.parent;
if (p.parent == null)
//P为根节点,跟节点为右节点
root = r;
else if (p.parent.left == p)
//将父节点指向p改为指向右节点
p.parent.left = r;
else
p.parent.right = r;
//右节点。left指向p
r.left = p;
//p.parent指向右节点
p.parent = r;
}
}
/** From CLR */
//设计很灵巧,自己的想法是一直判断,需要的时候递归,或者像责任链模式那样逐层像下
//第五种情况和第四种情况直接写在一个代码块中,第五种情况右单独写在一个if代码块中,
//这样的化,如果是第五种情况,执行if代码块后,变为第四种情况,直接执行第四种情况的代码块,
//操作时,颜色调整log(n)此,旋转最多2次
private void fixAfterInsertion(Entry<K,V> x) {
x.color = RED;
//第二种情况 父节点black时,不需要改变
//第三、四。。情况下父节点red,祖父节点一定为black
//只有第三中情况会进行循环
//x==null表明: 上次循环时,x.parant为root 循环结束
//x==root 循环结束
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) {
//第三种情况:父节点为祖父节点的左子节点,且叔节点red
//此时改变父节点、叔节点、祖父节点颜色,以祖父节点为根的子树符合标准,继续递归
setColor(parentOf(x), BLACK);
setColor(y, BLACK);
setColor(parentOf(parentOf(x)), RED);
x = parentOf(parentOf(x));
} else {
if (x == rightOf(parentOf(x))) {
//第五中情况:父节点为祖父节点的左子节点,且叔节点black,节点为父节点的右节点几点
//此时以父节点左旋,将节点重新赋值为父节点,变为第4种情况,
//然后直接执行第四种情况的操作
x = parentOf(x);
rotateLeft(x);
}
//第四种情况:父节点为祖父节点的左子节点,且叔节点black,节点为父节点的左几点
//此时以祖父节点右旋,然后改变节点颜色,完成
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;
}
public V remove(Object key) {
Entry<K,V> p = getEntry(key);
if (p == null)
return null;
V oldValue = p.value;
deleteEntry(p);
return oldValue;
}
/**
* 第三种情况右疑问
*
* 颜色转换log(n),旋转最多3次
*
* 将调整删除节点后的调整 和 第三种情况,未删除节点前直接调整,放在同一个方法中,难理解
*/
private void deleteEntry(Entry<K,V> p) {
modCount++;
size--;
//第六种情况:拥有两个节点,与节点的next互换位置后,变为第2-5钟情况
//只喜欢key,value值,其他值保留
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
Entry<K,V> replacement = (p.left != null ? p.left : p.right);
if (replacement != null) {
//第四种情况:拥有一个子节点,且节点red
//直接删除节点
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;
// Fix replacement
if (p.color == BLACK)
//第五种情况:拥有一个子节点,且节点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)
//第三种情况,没有子节点,且节点black
//通过调整,调整后变为第二种情况
//但是,p的指针指向不是变为root了吗??
fixAfterDeletion(p);
if (p.parent != null) {
//第二种情况,没有子节点,且节点red
//此时,直接删除节点
if (p == p.parent.left)
p.parent.left = null;
else if (p == p.parent.right)
p.parent.right = null;
p.parent = null;
}
}
}
/** From CLR */
//通过调整使x.parent到x下面节点路径上的黑节点数都增加1
private void fixAfterDeletion(Entry<K,V> x) {
while (x != root && colorOf(x) == BLACK) {
if (x == leftOf(parentOf(x))) {
Entry<K,V> sib = rightOf(parentOf(x));
if (colorOf(sib) == RED) {
//第一种情况:兄弟节点red,则其他节点都black
//以父节点,左旋,改变父节点red,兄弟节点black,变为第三、四、五种情况
setColor(sib, BLACK);
setColor(parentOf(x), RED);
rotateLeft(parentOf(x));
sib = rightOf(parentOf(x));
}
if (colorOf(leftOf(sib)) == BLACK &&
colorOf(rightOf(sib)) == BLACK) {
//第二种情况,兄弟节点black,兄弟节点两个子节点black
//改变兄弟节点red,此时父节点为根的子树,都少一个黑节点,继续递归
setColor(sib, RED);
x = parentOf(x);
} else {
if (colorOf(rightOf(sib)) == BLACK) {
//第四种情况,兄弟节点black,兄弟节点的左子节点red,右子节点blac
//改变兄弟节点的左子节点black,兄弟节点red,以兄弟节点右旋,变为第五种情况
setColor(leftOf(sib), BLACK);
setColor(sib, RED);
rotateRight(sib);
sib = rightOf(parentOf(x));
}
//第五种情况:兄节点black,兄节点的右子节点red,左子节点black
//兄弟节点颜色改变为父节点颜色,父节点颜色black,兄节点的右子节点red,以父节点左旋,完成
setColor(sib, colorOf(parentOf(x)));
setColor(parentOf(x), BLACK);
setColor(rightOf(sib), BLACK);
rotateLeft(parentOf(x));
x = root;
}
} else { // symmetric
Entry<K,V> sib = leftOf(parentOf(x));
if (colorOf(sib) == RED) {
setColor(sib, BLACK);
setColor(parentOf(x), RED);
rotateRight(parentOf(x));
sib = leftOf(parentOf(x));
}
if (colorOf(rightOf(sib)) == BLACK &&
colorOf(leftOf(sib)) == BLACK) {
setColor(sib, RED);
x = parentOf(x);
} else {
if (colorOf(leftOf(sib)) == BLACK) {
setColor(rightOf(sib), BLACK);
setColor(sib, RED);
rotateLeft(sib);
sib = leftOf(parentOf(x));
}
setColor(sib, colorOf(parentOf(x)));
setColor(parentOf(x), BLACK);
setColor(leftOf(sib), BLACK);
rotateRight(parentOf(x));
x = root;
}
}
}
//??
setColor(x, BLACK);
}
五、clear
/**
* 直接root变为null,其他交给gc
* 为什么不逐个元素清空?他们之间也有引用
* 虚拟机基本了解后再来解决吧
*/
public void clear() {
modCount++;
size = 0;
root = null;
}
六、内部类
TreeMap的内部类特别多
Entry:基本元素类
Values,KeySet,EntrySet: 用于生成集合,多数方式都是通过代理利用外部类的方法。
PrivateEntryIterator,KeyIterator,ValueIterator,EntryIterator,DescendingKeyIterator:迭代器类
SubMap:为了与以前的代码兼容
NavigableSubMap、AscendingSubMap、DescendingSubMap: 为了生成subMap,AscendingSubMap、DescendingSubMap继承与NavigableSubMap,NavigableSubMap基本实现了TreeMap的所有功能,并且嵌套了更多的静态内部类
红黑树看的头疼。。
参考:http://blog.csdn.net/jzhf2012/article/details/8540713
http://blog.csdn.net/jiang_bing/article/details/7537803
https://zh.wikipedia.org/wiki/%E7%BA%A2%E9%BB%91%E6%A0%91
http://yikun.github.io/2015/04/06/Java-TreeMap%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86%E5%8F%8A%E5%AE%9E%E7%8E%B0/