TreeMap的原理(jdk1.7)
TreeMap的底层实现基于二叉树的红黑树,插入的值是按一定顺序排序的。
TreeMap的构造方法
TreeMap有四个构造方法
1
public TreeMap() {
comparator = null;
}
创键空的TreeMap,采用自然排序
2
public TreeMap(Comparator<? super K> comparator) {
this.comparator = comparator;
}
创建一个空的TreeMap,排序是根据comparator排序的,
3
public TreeMap(Map<? extends K, ? extends V> m) {
comparator = null;
putAll(m);
}
创建一个新的TreeMap,m集合的值全部复制到TreeMap上,排序是用自然排序。运行时间的在n*log(n)时间内运行。
4
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) {
}
}
创建一个新的TreeMap,并键m的值全部复制到TreeMap上,排序用的是m中指定的排序。这个方法运行时间是在线性时间内。
TreeMap的put()方法
public V put(K key, V value) {
Entry<K,V> t = root;
/*如果此时的红黑树为null,即这是插入的第一个节点,直接设置为根节点*/
if (t == null) {
/*类型检查,不能为null*/
compare(key, key);
root = new Entry<>(key, value, null);
size = 1;
modCount++;
return null;
}
int cmp;
Entry<K,V> parent;
Comparator<? super K> cpr = comparator;
/*判断该TreeMap在创建时是否制定了Comparator,若是,排序使用Comparatr中的compare()方法,没有则使用默认的Comparable的自然排序*/
if (cpr != null) {
/*循环红黑书,能匹配到key就替换value*/
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);
if (cmp < 0)
parent.left = e;
else
parent.right = e;
//添加完节点,开始维护红黑树
fixAfterInsertion(e);
size++;
modCount++;
return null;
}
因为是根据key排序的,所以要求TreeMap中的key数据类型要一致,不然会报ClassCastException。
Comparable("自然排序")
在java中,有一个接口类Comparable。该类有一个方法compareTo(T o)。所有的封装基本类型都实现了该接口并重写了这个方法。compareTo()就是我们常说的自然排序。注意:key不能为null,因为会调用key.compareTo()方法。
例子:
Map treeMap = new TreeMap();
Comparator(比较器)
TreeMap中使用的比较器。若我们不想用自然排序设计的比较规则,想自己设计一套规则,则需要创建该接口的示例,并实现compare()方法,在创建TreeMap时通过构造方法传入。注意:key可以为null,如果你想限制你可以在Comparator的compare()方法里面去限制。
例子:
Comparator comparator = new Comparator() {
@Override
public int compare(Object o1, Object o2) {
if(o1.toString().length()>o2.toString().length()){
return 1;
}else{
return -1;
}
}
};
Map treeMap = new TreeMap(comparator);
TreeMap的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) {
// 区别是自然排序还是Comparator排序
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;
}
TreeMap的get()倒是没什么奇特之处,只是要区别是自然排序和Comparator排序,根据不同的排序调用不同的比较方法去定位想要的数据。因为底层是红黑树,所以检索的速度相当快,时间复杂度为O(log(n))。
例子
用默认自然排序:
Map treeMap = new TreeMap();
treeMap.put("1","1");
treeMap.put("2","2");
treeMap.put("7","7");
treeMap.put("3","3");
treeMap.put("8","8");
treeMap.put("4","4");
treeMap.put("5","5");
Set keySet = treeMap.keySet();
Iterator keyItr = keySet.iterator();
while(keyItr.hasNext()){
String key = (String)keyItr.next();
String value = (String)treeMap.get(key);
System.out.println(value);
}
输出结果:
1
2
3
4
5
7
8
使用比较器comparator
public void comparatorTest(){
class DemoComparator implements Comparator<String>{
@Override
public int compare(String o1, String o2) {
if(o1.length()==o2.length() && o1.equals(o2)){
return 0;
}else if(o1.length()<o2.length()){
return 1;
}else{
return -1;
}
}
}
Map treeMap = new TreeMap(new DemoComparator());
treeMap.put("111","1");
treeMap.put("2","2");
treeMap.put("71","7");
treeMap.put("31111","3");
treeMap.put("8111","8");
treeMap.put("4111111","4");
treeMap.put("511111","5");
Set keySet = treeMap.keySet();
Iterator keyItr = keySet.iterator();
while(keyItr.hasNext()){
String key = (String)keyItr.next();
System.out.println("key:"+key);
String value = (String)treeMap.get(key);
System.out.println("value:"+value);
}
}
结果:
key:4111111,value:4
key:511111,value:5
key:31111,value:3
key:8111,value:8
key:111,value:1
key:71,value:7
key:2,value:2
简单的设计一个根据key字符串长度来排序的比较器。