源码的魅力 - TreeMap 的工作原理
2017-09-14 本文已影响0人
Nichool
源码的魅力 - TreeMap 的工作原理(Android 7.1源码)
简介
由于HashMap与linkedHashMap都不能按照key的数据顺序进行遍历,所以后来就有了TreeMap。
怎么做到按照插入顺序排序的呢
public TreeMap(Comparator<? super K> comparator) {
this.comparator = comparator;
}
public V put(K key, V value) {
TreeMapEntry<K,V> t = root;
if (t == null) {
if (comparator != null) {
if (key == null) {
comparator.compare(key, key);
}
} else {
if (key == null) {
throw new NullPointerException("key == null");
} else if (!(key instanceof Comparable)) {
throw new ClassCastException(
"Cannot cast" + key.getClass().getName() + " to Comparable.");
}
}
root = new TreeMapEntry<>(key, value, null);
size = 1;
modCount++;
return null;
}
int cmp;
TreeMapEntry<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();
@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);
}
TreeMapEntry<K,V> e = new TreeMapEntry<>(key, value, parent);
if (cmp < 0)
parent.left = e;
else
parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
return null;
}
TreeMap存在一个参数为Comparator的构造函数,在插入数据时默认是使用数据的默认比较器,否则使用比较器,通过比较器比较的值,如果相等则直接替换,如果不同则插入,使用红黑树维护整个结构。
怎么获取数据时是有序的呢
abstract class PrivateEntryIterator<T> implements Iterator<T> {
TreeMapEntry<K,V> next;
TreeMapEntry<K,V> lastReturned;
...
final TreeMapEntry<K,V> nextEntry() {
TreeMapEntry<K,V> e = next;
if (e == null)
throw new NoSuchElementException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
next = successor(e);
lastReturned = e;
return e;
}
}
//中序遍历查找下一个节点
static <K,V> TreeMapEntry<K,V> successor(TreeMapEntry<K,V> t) {
if (t == null)
return null;
else if (t.right != null) {
TreeMapEntry<K,V> p = t.right;
while (p.left != null)
p = p.left;
return p;
} else {
TreeMapEntry<K,V> p = t.parent;
TreeMapEntry<K,V> ch = t;
while (p != null && ch == p.right) {
ch = p;
p = p.parent;
}
return p;
}
}
通过PrivateEntryIterator遍历器然后,通过中序遍历返回数据,正是排序的数据。