前面,通过学习HashMap和HashTable后,我们对Map的学习已经有个简单了了解,接下来,我们来学习Treemap。和之前一样,我们先对TreeMap有个系统的认识,接着学习它的源码,最后再通过代码示例掌握它的使用方法。
TreeMap是一个有序的Key-Value集合,底层是通过红黑树实现的; TreeMap继承于AbstractMap,所以也是一个键值对方式的Map; TreeMap实现了NavigableMap接口,意味着它支持一系列的导航方法,比如返回有序的key集合; TreeMap实现了Cloneable接口,意味着它能被克隆; TreeMap实现了java.io.Serializable接口,意味着它支持序列化。 由以上得到: TreeMap是基于红黑树实现的,根据具体使用的构造方法,该映射根据其键值的自然顺序进行排序的,或者根据创建映射时提供的Comparator进行排序。 TreeMap是非同步的,它的Iterator方法的迭代器是Fail-Fast机制的。并且它的containKey、get、put和remove的时间复杂度是log(n)(效率高,是一个非常重要的性质)。
面试易考点:
关注点 | 结论 |
---|---|
结合底层实现的数据结构 | 红黑树 |
集合中元素是否允许为空 | key、value值都不允许为空 |
是否允许数据重复 | key值不允许重复,value值允许重复 |
是否有序 | 有序 |
是否线程安全 | 非线程安全(是非同步) |
1>理解部分概念 TreeMap是通过红黑树实现的,TreeMap存储的是Key-Value键值对,TreeMap的排序是基于对键Key的排序; TreeMap提供了操作Key、Key-Value、Value等方法,同时提供了对TreeMap整棵树进行操作的方法。 红黑树简要补充: R-B Tree,全称是Red-Black Tree,又称为“红黑树”,它一种特殊的二叉查找树。红黑树的每个节点上都有存储位表示节点的颜色,可以是红(Red)或黑(Black)。 红黑树的特性: (1)每个节点或者是黑色,或者是红色。 (2)根节点是黑色。 (3)每个叶子节点(NIL)是黑色。 [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!] (4)如果一个节点是红色的,则它的子节点必须是黑色的。 (5)从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。 红黑树基本构造如下:
2>TreeMap的构造函数 1、默认构造函数,使用java的默认的比较器比较Key的大小,从而对TreeMap进行排序
public TreeMap() { comparator = null;}2、带比较器的构造函数
public TreeMap(Comparator<? super K> comparator) { this.comparator = comparator;}3、带Map的构造函数,Map会成为TreeMap的子集
public TreeMap(Map<? extends K, ? extends V> m) { comparator = null; putAll(m);}上面代码中会调用putAll(),将m中的所有元素添加到TreeMap中,putAll()源码如下:
public void putAll(Map<? extends K, ? extends V> m) { for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) put(e.getKey(), e.getValue());}从中,我们可以得到putAll()就是将m中的key-value逐个的添加到TreeMap中。 4、带sortedMap的构造函数,SortedMap会成为TreeMap的子集
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) { }}该构造函数不同于上面的构造函数,在上一个构造函数中传入的参数是Map,Map不是有序的,所以要逐个的添加key,value值。而该构造函数的参数是SortMap,是一个有序的Map,我们通过buildFromSorted()来创建对应的Map。buildFromSorted()代码如下:
// 根据已经一个排好序的map创建一个TreeMap // 将map中的元素逐个添加到TreeMap中,并返回map的中间元素作为根节点。 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 { if (hi < lo) return null; // 获取中间元素 int mid = (lo + hi) / 2; Entry<K,V> left = null; // 若lo小于mid,则递归调用获取(middel的)左孩子。 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<K,V> entry = (Map.Entry<K,V>)it.next(); key = entry.getKey(); value = entry.getValue(); } else { key = (K)it.next(); value = defaultVal; } } else { // use stream key = (K) str.readObject(); value = (defaultVal != null ? defaultVal : (V) str.readObject()); } // 创建middle节点 Entry<K,V> middle = new Entry<K,V>(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) { // 递归调用获取(middel的)右孩子。 Entry<K,V> right = buildFromSorted(level+1, mid+1, hi, redLevel, it, str, defaultVal); // 设置middle为left的父亲,left为middle的左孩子 middle.right = right; right.parent = middle; } return middle; }重要理解以下几点: a、buildFromSorted()是通过递归将SortedMap中的元素逐个关联; b、buildFromSorted()返回middle节点(中间节点)作为root; c、buildFromSorted添加到红黑树中时,只是将level==redLevel的节点设为红色。第level级节点,实际上是buildFromSorted转换成红黑树的最底端的节点;只将红黑树最底端的阶段着色为红色,其余为黑色。
1、遍历TreeMap的键值对 一是根据entrySet()获取TreeMap的键值对的Set的集合; 二是通过Iterator迭代器遍历第一步得到的集合。
// 假设map是TreeMap对象// map中的key是String类型,value是Integer类型Integer integ = null;Iterator iter = map.entrySet().iterator();while(iter.hasNext()) { Map.Entry entry = (Map.Entry)iter.next(); // 获取key key = (String)entry.getKey(); // 获取value integ = (Integer)entry.getValue();}2、遍历TreeMap的键 一是根据keySet()获取TreeMap的键的Set集合; 二是通过Iterator迭代器遍历第一步得到的集合。
// 假设map是TreeMap对象// map中的key是String类型,value是Integer类型String key = null;Integer integ = null;Iterator iter = map.keySet().iterator();while (iter.hasNext()) { // 获取key key = (String)iter.next(); // 根据key,获取value integ = (Integer)map.get(key);}3、遍历TreeMap的值 一是根据value()获取TreeMap的值的集合; 二是通过Iterator迭代器遍历第一步得到的集合
// 假设map是TreeMap对象// map中的key是String类型,value是Integer类型Integer value = null;Collection c = map.values();Iterator iter= c.iterator();while (iter.hasNext()) { value = (Integer)iter.next();}运行结果如下:
---- testTreeMapOridinaryAPIs ----{one=5, three=8, two=1}next : one - 5next : three - 8next : two - 1size: 3contains key two : truecontains key five : falsecontains value 0 : falsetmap:{one=5, two=1}tmap is empty文章只是作为自己的学习笔记,借鉴了网上的许多案例,如果觉得阔以的话,希望多交流,在此 谢过…
新闻热点
疑难解答