一、TreeMap 类概述

  1、TreeMap存储 Key-Value 对时,要求key必须是由同一个类创建的对象,需要根据 key-value 对进行排序,TreeMap 可以保证所有的 Key-Value 对处于有序状态

  2、TreeSet底层使用红黑树结构存储数据

  3、TreeMap 的 Key 的排序:

    自然排序:TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException
    定制排序:创建 TreeMap 时,传入一个 Comparator 对象,该对象负责对TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现
Comparable 接口

  4、TreeMap判断两个key相等的标准:两个key通过compareTo()方法或者compare()方法返回0。

  5、TreeMap和HashMap一样实现的是Map接口,但两者的实现方式天差地别。HashMap的底层是hash表+单向链表的形式存储数据,TreeMap底层是通过红黑树存储数据。HashMap因为是基于散列表的实现,所以时间开销为O(1),TreeMap的时间开销是O(logn)。TreeMap的优势在于他是基于key值排序的。

  

  关于红黑树: 

    红黑树有五大特性:
    1)每个结点要么是红的,要么是黑的。
    2)根结点是黑的。
    3)每个叶结点,即空结点(NIL)是黑的。
    4)如果一个结点是红的,那么它的俩个儿子都是黑的。
    5)对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点。

    

    他的所有操作都是围绕着这五大特性展开的。这五大特性的最终目的就是为了维持二叉树的相对平衡性。

    当每次二叉树操作以后,有可能会出现违反特性的情况(也就是出现了失衡状况),这时二叉树需要通过左旋,右旋,重新着色等系列操作,再次找到平衡点。

    红黑色的操作就两个要点。第一:遵循二叉查找树的规范,对所有元素进行排序,但这里存在着不确定情况,有可能出现左右子树深度极其不对称的情况,导致最坏时间复杂度出现O(n)的情况。 第二:正因为存在二叉树严重不平衡的情况,所以就出现了红黑二叉树,通过标记每个节点的颜色,动态的调整二叉树的结构,使其始终维持在相对平衡的状态,这样做的好处就是查找性能始终维持在O(logn)的较高水平。

   

二、TreeMap 类结构

  1、TreeMap 类继承结构

    

 

  2、TreeMap 类签名

public class TreeMap<K,V>
    extends AbstractMap<K,V>
    implements NavigableMap<K,V>, Cloneable, java.io.Serializable{}

    TreeMap 实现了 Map 接口,其内部数据格式是“键-值对”的形式(Entry),排列顺序是按照键的顺序进行的。

  3、TreeMap 方法列表

    

 

三、TreeMap 成员变量

 1     /**
 2      * The comparator used to maintain order in this tree map, or
 3      * null if it uses the natural ordering of its keys.
 4      *
 5      * TreeMap 内部的比较器,若为空,则为自然顺序
 6      */
 7     private final Comparator<? super K> comparator;
 8 
 9     // 根节点
10     private transient Entry<K,V> root;
11 
12     /**
13      * The number of entries in the tree
14      */
15     private transient int size = 0;
16 
17     /**
18      * The number of structural modifications to the tree.
19      */
20     private transient int modCount = 0;

 

四、TreeMap 构造器

  TreeMap 有四个构造器,分别如下:

  构造器一:无参构造器

1 /**
2  * 无参构造器。使用 key 的自然顺序排列(key 要实现 Comparable 接口)
3  */
4 public TreeMap() {
5     comparator = null;
6 }

 

  构造器二:

1 /**
2  * 使用指定的 Comparator(比较器)构造一个空的 TreeMap
3  */
4 public TreeMap(Comparator<? super K> comparator) {
5     this.comparator = comparator;
6 }

 

  构造器三:

1 /**
2  * 使用给定的 Map 构造一个 TreeMap
3  */
4 public TreeMap(Map<? extends K, ? extends V> m) {
5     comparator = null;
6     putAll(m);
7 }

 

  构造器四:

 1 /**
 2  * 使用给定的 SortedMap 构造一个 TreeMap
 3  *(使用 SortedMap 的顺序)
 4  */
 5 public TreeMap(SortedMap<K, ? extends V> m) {
 6     comparator = m.comparator();
 7     try {
 8         buildFromSorted(m.size(), m.entrySet().iterator(), null, null);
 9     } catch (java.io.IOException cannotHappen) {
10     } catch (ClassNotFoundException cannotHappen) {
11     }
12 }

 

五、常用方法

  1、查找某个 key

 1 // 判断 TreeMap 是否包含某个 key
 2 public boolean containsKey(Object key) {
 3     return getEntry(key) != null;
 4 }
 5 
 6 // 查找 TreeMap 中某个 key 对应的 value(若不存在返回 null)
 7 public V get(Object key) {
 8     Entry<K,V> p = getEntry(key);
 9     return (p==null ? null : p.value);
10 }

 

    由于这两个方法内部都是通过 getEntry 方法实现,因此放在一起分析,如下:

 1 final Entry<K,V> getEntry(Object key) {
 2     // Offload comparator-based version for sake of performance
 3     if (comparator != null)
 4         return getEntryUsingComparator(key);
 5     if (key == null)
 6         throw new NullPointerException();
 7     @SuppressWarnings("unchecked")
 8         Comparable<? super K> k = (Comparable<? super K>) key;
 9     Entry<K,V> p = root;
10     while (p != null) {
11         int cmp = k.compareTo(p.key);
12         if (cmp < 0)
13             p = p.left;
14         else if (cmp > 0)
15             p = p.right;
16         else
17             return p;
18     }
19     return null;
20 }

 

    当 Comparator 不为空时,使用如下方法查找:

 1 /**
 2  * Version of getEntry using comparator. Split off from getEntry
 3  * for performance. (This is not worth doing for most methods,
 4  * that are less dependent on comparator performance, but is
 5  * worthwhile here.)
 6  */
 7 final Entry<K,V> getEntryUsingComparator(Object key) {
 8     @SuppressWarnings("unchecked")
 9         K k = (K) key;
10     Comparator<? super K> cpr = comparator;
11     if (cpr != null) {
12         Entry<K,V> p = root;
13         while (p != null) {
14             int cmp = cpr.compare(k, p.key);
15             if (cmp < 0)
16                 p = p.left;
17             else if (cmp > 0)
18                 p = p.right;
19             else
20                 return p;
21         }
22     }
23     return null;
24 }

 

   可以看到,这两个方法都是二叉查找树的查找过程。

   PS: 这里将 Comporator 和 Comparable 两个接口分开进行操作。注释说明是出于性能考虑,虽然大部分方法中不值得这样做,但这里值得。

  2、查找某个 value

1 public boolean containsValue(Object value) {
2     for (Entry<K,V> e = getFirstEntry(); e != null; e = successor(e))
3         if (valEquals(value, e.value))
4             return true;
5     return false;
6 }

 

    getFirstEntry() 方法是获取第一个 Entry 节点(中序遍历最左边的节点):

 1 /**
 2  * Returns the first Entry in the TreeMap (according to the TreeMap's
 3  * key-sort function).  Returns null if the TreeMap is empty.
 4  */
 5 final Entry<K,V> getFirstEntry() {
 6     Entry<K,V> p = root;
 7     if (p != null)
 8         while (p.left != null)
 9             p = p.left;
10     return p;
11 }

 

    查找某个 Entry 的后继节点:

 1 /**
 2  * Returns the successor of the specified Entry, or null if no such.
 3  */
 4 static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) {
 5     if (t == null)
 6         return null;
 7     // 若右子树不为空,则后继节点就是右子树的最小节点
 8     else if (t.right != null) {
 9         Entry<K,V> p = t.right;
10         while (p.left != null)
11             p = p.left;
12         return p;
13     } else {
14         // 若右子树为空,则向上回溯
15         Entry<K,V> p = t.parent;
16         Entry<K,V> ch = t;
17         while (p != null && ch == p.right) {
18             ch = p;
19             p = p.parent;
20         }
21         return p;
22     }
23 }

    可以看到,这里判断 TreeMap 是否包含某个 value,是按照二叉查找树的中序遍历去比较是否存在与给定 value 相等的值。

 

  3、lowerEntry / lowerKey: 查找比指定 key 小的最大 Entry / key

1 public Map.Entry<K,V> lowerEntry(K key) {
2     return exportEntry(getLowerEntry(key));
3 }
4 
5 public K lowerKey(K key) {
6     return keyOrNull(getLowerEntry(key));
7 }

 

 1 /**
 2  * Returns the entry for the greatest key less than the specified key; if
 3  * no such entry exists (i.e., the least key in the Tree is greater than
 4  * the specified key), returns {@code null}.
 5  */
 6 final Entry<K,V> getLowerEntry(K key) {
 7     Entry<K,V> p = root;
 8     while (p != null) {
 9         int cmp = compare(key, p.key);
10         // 给定的key大于根节点,继续与右子节点比较
11         if (cmp > 0) {
12             if (p.right != null)
13                 p = p.right;
14             else
15                 return p;
16         } else {
17             // 左子节点不为空,则为左子节点
18             if (p.left != null) {
19                 p = p.left;
20             } else {
21                 // 左子节点为空,向父节点上溯
22                 Entry<K,V> parent = p.parent;
23                 Entry<K,V> ch = p;
24                 while (parent != null && ch == parent.left) {
25                     ch = parent;
26                     parent = parent.parent;
27                 }
28                 return parent;
29             }
30         }
31     }
32     return null;
33 }

 

  4、higherEntry / higherKey: 查找比指定 key 大的最小 Entry / key

1 public Map.Entry<K,V> higherEntry(K key) {
2     return exportEntry(getHigherEntry(key));
3 }
4 
5 public K higherKey(K key) {
6     return keyOrNull(getHigherEntry(key));
7 }

 

    getHigherEntry 方法与 getLowerEntry 方法实现类似,不同之处在于 left 和 right 相反,这里不再贴代码。

  5、floorEntry / floorKey

1 public Map.Entry<K,V> floorEntry(K key) {
2     return exportEntry(getFloorEntry(key));
3 }
4 
5 public K floorKey(K key) {
6     return keyOrNull(getFloorEntry(key));
7 }

 

 1 /**
 2  * Gets the entry corresponding to the specified key; if no such entry
 3  * exists, returns the entry for the greatest key less than the specified
 4  * key; if no such entry exists, returns {@code null}.
 5  */
 6 final Entry<K,V> getFloorEntry(K key) {
 7     Entry<K,V> p = root;
 8     while (p != null) {
 9         int cmp = compare(key, p.key);
10         if (cmp > 0) {
11             if (p.right != null)
12                 p = p.right;
13             else
14                 return p;
15         } else if (cmp < 0) {
16             if (p.left != null) {
17                 p = p.left;
18             } else {
19                 Entry<K,V> parent = p.parent;
20                 Entry<K,V> ch = p;
21                 while (parent != null && ch == parent.left) {
22                     ch = parent;
23                     parent = parent.parent;
24                 }
25                 return parent;
26             }
27         } else
28             // 与上述方法的区别
29             return p;
30     }
31     return null;
32 }

 

  查找指定 key 关联的 Entry;若不存在,返回比该 key 小的最大 key 关联的 Entry;若这也不存在则返回 null。

  PS: 该方法与上面的 getLowerEntry 方法仅相差 while 循环内部的一个 else。

 

  6、ceilingEntry / ceilKey:

1 public Map.Entry<K,V> ceilingEntry(K key) {
2     return exportEntry(getCeilingEntry(key));
3 }
4 
5 public K ceilingKey(K key) {
6     return keyOrNull(getCeilingEntry(key));
7 }

 

    getCeilingEntry 方法与 getFloorEntry 方法实现类似,也是 left 和 right 相反。就像上面 getLowerEntry 和 getHigherEntry 的区别那样,这里不再贴代码。

    查找指定 key 关联的 Entry;若不存在,返回比该 key 大的最小 key 关联的 Entry;若这也不存在则返回 null。

  7、其他方法

1 public NavigableMap<K,V> headMap(K toKey, boolean inclusive) {
2     return new AscendingSubMap<>(this,
3                                  true,  null,  true,
4                                  false, toKey, inclusive);
5 }

 

1 public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) {
2     return new AscendingSubMap<>(this,
3                                  false, fromKey, inclusive,
4                                  true,  null,    true);
5 }

 

1 public NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,
2                                 K toKey,   boolean toInclusive) {
3     return new AscendingSubMap<>(this,
4                                  false, fromKey, fromInclusive,
5                                  false, toKey,   toInclusive);
6 }

 

 

六、插入操作

  该操作其实就是红黑树的插入节点操作。前面分析过,红黑树是一种平衡二叉树,新增节点后可能导致其失去平衡,因此需要对其进行修复操作以维持其平衡性。插入操作的代码如下:

 1 public V put(K key, V value) {
 2     Entry<K,V> t = root;
 3     // 若 root 节点为空,则直接插入(为根节点)
 4     if (t == null) {
 5         compare(key, key); // type (and possibly null) check
 6         root = new Entry<>(key, value, null);
 7         size = 1;
 8         modCount++;
 9         return null;
10     }
11     int cmp;
12     Entry<K,V> parent;
13     // split comparator and comparable paths
14     // 拆分 Comparator 接口和 Comparable 接口(上文 getEntry 方法也是如此)
15     Comparator<? super K> cpr = comparator;
16     if (cpr != null) {
17         do {
18             parent = t;
19             cmp = cpr.compare(key, t.key);
20             if (cmp < 0)
21                 t = t.left;
22             else if (cmp > 0)
23                 t = t.right;
24             else
25                 // 若key已存在,则替换其对应的value
26                 return t.setValue(value);
27         } while (t != null);
28     }
29     else {
30         if (key == null)
31             throw new NullPointerException();
32         @SuppressWarnings("unchecked")
33             Comparable<? super K> k = (Comparable<? super K>) key;
34         do {
35             parent = t;
36             cmp = k.compareTo(t.key);
37             if (cmp < 0)
38                 t = t.left;
39             else if (cmp > 0)
40                 t = t.right;
41             else
42                 return t.setValue(value);
43         } while (t != null);
44     }
45     Entry<K,V> e = new Entry<>(key, value, parent);
46     if (cmp < 0)
47         parent.left = e;
48     else
49         parent.right = e;
50     // 插入节点后的平衡性调整
51     fixAfterInsertion(e);
52     size++;
53     modCount++;
54     return null;
55 }

 

  对应的几种插入节点修复操作前文「数据结构与算法笔记」已进行了分析,为了便于分析和理解代码,这里把图再贴一下(下图为关注节点的父节点是其祖父节点的左子节点的情况,在右边时操作类似):

 

  case1: 关注节点 a 的叔叔节点为红色

  

 

  case2: 关注节点为 a,它的叔叔节点 d 是黑色,a 是其父节点 b 的右子节点

  

 

   case3: 关注节点是 a,它的叔叔节点 d 是黑色,a 是其父节点 b 的左子节点

   

 

  插入操作的平衡调整代码如下:

 1 private void fixAfterInsertion(Entry<K,V> x) {
 2     // 新插入的节点为红色
 3     x.color = RED;
 4     // 只有在父节点为红色时需要进行插入修复操作
 5     while (x != null && x != root && x.parent.color == RED) {
 6         // 下面两种情况是左右对称的
 7         // x 的父节点是它祖父节点的左子节点
 8         if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
 9             // 叔叔节点
10             Entry<K,V> y = rightOf(parentOf(parentOf(x)));
11             // case1
12             if (colorOf(y) == RED) {
13                 setColor(parentOf(x), BLACK);
14                 setColor(y, BLACK);
15                 setColor(parentOf(parentOf(x)), RED);
16                 x = parentOf(parentOf(x));
17             } else {
18                 // case2
19                 if (x == rightOf(parentOf(x))) {
20                     x = parentOf(x);
21                     rotateLeft(x);
22                 }
23                 // case3
24                 setColor(parentOf(x), BLACK);
25                 setColor(parentOf(parentOf(x)), RED);
26                 rotateRight(parentOf(parentOf(x)));
27             }
28         } 
29         // x 的父节点是它祖父节点的右子节点(与上面情况对称)
30         else {
31             Entry<K,V> y = leftOf(parentOf(parentOf(x)));
32             if (colorOf(y) == RED) {
33                 setColor(parentOf(x), BLACK);
34                 setColor(y, BLACK);
35                 setColor(parentOf(parentOf(x)), RED);
36                 x = parentOf(parentOf(x));
37             } else {
38                 if (x == leftOf(parentOf(x))) {
39                     x = parentOf(x);
40                     rotateRight(x);
41                 }
42                 setColor(parentOf(x), BLACK);
43                 setColor(parentOf(parentOf(x)), RED);
44                 rotateLeft(parentOf(parentOf(x)));
45             }
46         }
47     }
48     root.color = BLACK;
49 }

 

七、删除操作

  remove() 方法:

1 public V remove(Object key) {
2     Entry<K,V> p = getEntry(key);
3     if (p == null)
4         return null;
5     V oldValue = p.value;
6     deleteEntry(p);
7     return oldValue;
8 }

 

  内部实现方法如下:

 1 /**
 2  * Delete node p, and then rebalance the tree.
 3  */
 4 private void deleteEntry(Entry<K,V> p) {
 5     modCount++;
 6     size--;
 7     // If strictly internal, copy successor's element to p and then make p
 8     // point to successor.
 9     // 左右子树都不为空,寻找后继节点
10     if (p.left != null && p.right != null) {
11         Entry<K,V> s = successor(p);
12         p.key = s.key;
13         p.value = s.value;
14         p = s;
15     } // p has 2 children
16     // Start fixup at replacement node, if it exists.
17     Entry<K,V> replacement = (p.left != null ? p.left : p.right);
18     if (replacement != null) {
19         // Link replacement to parent
20         replacement.parent = p.parent;
21         if (p.parent == null)
22             root = replacement;
23         else if (p == p.parent.left)
24             p.parent.left  = replacement;
25         else
26             p.parent.right = replacement;
27         // Null out links so they are OK to use by fixAfterDeletion.
28         p.left = p.right = p.parent = null;
29         // Fix replacement
30         if (p.color == BLACK)
31             fixAfterDeletion(replacement);
32     } else if (p.parent == null) { // return if we are the only node.
33         // 只有一个根节点
34         root = null;
35     } else { //  No children. Use self as phantom replacement and unlink.
36         if (p.color == BLACK)
37             fixAfterDeletion(p);
38         if (p.parent != null) {
39             if (p == p.parent.left)
40                 p.parent.left = null;
41             else if (p == p.parent.right)
42                 p.parent.right = null;
43             p.parent = null;
44         }
45     }
46 }

 

  几种删除操作情况如下(下图为关注节点为父节点的左子节点的情况,关注节点为父节点的右子节点情况时的操作对称):

   case1: 关注节点的兄弟节点是红色

    

 

   case2: 关注节点的兄弟节点是黑色,且兄弟节点的子节点都是黑色

    

 

   case3: 关注节点的兄弟节点是黑色,且左子节点是红色、右子节点是黑色

    

 

  case4: 关注节点的兄弟节点是黑色,且右子节点是红色、左子节点是黑色

    

 

     两天又参考了其他文章及代码,这里的 case4 是目前经分析认为比较准确的(符合 JDK 1.8 源码中 TreeMap 的实现思路)。

    删除操作的平衡调整代码如下:

 1 private void fixAfterDeletion(Entry<K,V> x) {
 2     // x 不为根节点,且颜色为黑色
 3     while (x != root && colorOf(x) == BLACK) {
 4         // x 是父节点的左子节点
 5         if (x == leftOf(parentOf(x))) {
 6             // 兄弟节点
 7             Entry<K,V> sib = rightOf(parentOf(x));
 8             // case1 待删除节点的兄弟节点为红色
 9             if (colorOf(sib) == RED) {
10                 setColor(sib, BLACK);
11                 setColor(parentOf(x), RED);
12                 rotateLeft(parentOf(x));
13                 sib = rightOf(parentOf(x));
14             }
15             // case2 待删除节点的兄弟节点的子节点都为黑色
16             if (colorOf(leftOf(sib))  == BLACK && colorOf(rightOf(sib)) == BLACK) {
17                 setColor(sib, RED);
18                 x = parentOf(x);
19             } else {
20                 // case3 待删除节点的兄弟节点的左子节点为红色、右子节为黑色
21                 if (colorOf(rightOf(sib)) == BLACK) {
22                     setColor(leftOf(sib), BLACK);
23                     setColor(sib, RED);
24                     rotateRight(sib);
25                     sib = rightOf(parentOf(x));
26                 }
27                 // case4 待删除节点的兄弟节点的左子节点为黑色、右子节为红色
28                 setColor(sib, colorOf(parentOf(x)));
29                 setColor(parentOf(x), BLACK);
30                 setColor(rightOf(sib), BLACK); //??
31                 rotateLeft(parentOf(x));
32                 x = root;
33             }
34         }
35         // x 是父节点的右子节点(对称操作)
36         else { // symmetric
37             Entry<K,V> sib = leftOf(parentOf(x));
38             if (colorOf(sib) == RED) {
39                 setColor(sib, BLACK);
40                 setColor(parentOf(x), RED);
41                 rotateRight(parentOf(x));
42                 sib = leftOf(parentOf(x));
43             }
44             if (colorOf(rightOf(sib)) == BLACK &&
45                 colorOf(leftOf(sib)) == BLACK) {
46                 setColor(sib, RED);
47                 x = parentOf(x);
48             } else {
49                 if (colorOf(leftOf(sib)) == BLACK) {
50                     setColor(rightOf(sib), BLACK);
51                     setColor(sib, RED);
52                     rotateLeft(sib);
53                     sib = leftOf(parentOf(x));
54                 }
55                 setColor(sib, colorOf(parentOf(x)));
56                 setColor(parentOf(x), BLACK);
57                 setColor(leftOf(sib), BLACK);
58                 rotateRight(parentOf(x));
59                 x = root;
60             }
61         }
62     }
63     setColor(x, BLACK);
64 }

 

  插入和删除操作相对复杂,容易被绕晕,但其实也是有规律可循的。对比操作的图解,可以更容易分析和理解。

 

八、TreeMap 案例

  1、自然排序

    集合中要放入的对象:需要重写 equals 和 hashCode 方法

 1 public class User implements Comparable{
 2     private String name;
 3     private int age;
 4 
 5     public User() {
 6     }
 7 
 8     public User(String name, int age) {
 9         this.name = name;
10         this.age = age;
11     }
12 
13     public String getName() {
14         return name;
15     }
16 
17     public void setName(String name) {
18         this.name = name;
19     }
20 
21     public int getAge() {
22         return age;
23     }
24 
25     public void setAge(int age) {
26         this.age = age;
27     }
28 
29     @Override
30     public String toString() {
31         return "User{" +
32                 "name='" + name + '\'' +
33                 ", age=" + age +
34                 '}';
35     }
36 
37     @Override
38     public boolean equals(Object o) {
39         System.out.println("User equals()....");
40         if (this == o) return true;
41         if (o == null || getClass() != o.getClass()) return false;
42 
43         User user = (User) o;
44 
45         if (age != user.age) return false;
46         return name != null ? name.equals(user.name) : user.name == null;
47     }
48 
49     @Override
50     public int hashCode() { //return name.hashCode() + age;
51         int result = name != null ? name.hashCode() : 0;
52         result = 31 * result + age;
53         return result;
54     }
55 
56     //按照姓名从大到小排列,年龄从小到大排列
57     @Override
58     public int compareTo(Object o) {
59         if(o instanceof User){
60             User user = (User)o;
61 //            return -this.name.compareTo(user.name);
62             int compare = -this.name.compareTo(user.name);
63             if(compare != 0){
64                 return compare;
65             }else{
66                 return Integer.compare(this.age,user.age);
67             }
68         }else{
69             throw new RuntimeException("输入的类型不匹配");
70         }
71 
72     }
73 }

 

 1     @Test
 2     public void test1(){
 3         TreeMap map = new TreeMap();
 4         User u1 = new User("Tom",23);
 5         User u2 = new User("Jerry",32);
 6         User u3 = new User("Jack",20);
 7         User u4 = new User("Rose",18);
 8 
 9         map.put(u1,98);
10         map.put(u2,89);
11         map.put(u3,76);
12         map.put(u4,100);
13 
14         Set entrySet = map.entrySet();
15         Iterator iterator1 = entrySet.iterator();
16         while (iterator1.hasNext()){
17             Object obj = iterator1.next();
18             Map.Entry entry = (Map.Entry) obj;
19             System.out.println(entry.getKey() + "---->" + entry.getValue());
20 
21         }
22     }

 

  2、定制排序

 1     //定制排序
 2     @Test
 3     public void test2(){
 4         TreeMap map = new TreeMap(new Comparator() {
 5             @Override
 6             public int compare(Object o1, Object o2) {
 7                 if(o1 instanceof User && o2 instanceof User){
 8                     User u1 = (User)o1;
 9                     User u2 = (User)o2;
10                     return Integer.compare(u1.getAge(),u2.getAge());
11                 }
12                 throw new RuntimeException("输入的类型不匹配!");
13             }
14         });
15         User u1 = new User("Tom",23);
16         User u2 = new User("Jerry",32);
17         User u3 = new User("Jack",20);
18         User u4 = new User("Rose",18);
19 
20         map.put(u1,98);
21         map.put(u2,89);
22         map.put(u3,76);
23         map.put(u4,100);
24 
25         Set entrySet = map.entrySet();
26         Iterator iterator1 = entrySet.iterator();
27         while (iterator1.hasNext()){
28             Object obj = iterator1.next();
29             Map.Entry entry = (Map.Entry) obj;
30             System.out.println(entry.getKey() + "---->" + entry.getValue());
31 
32         }
33     }

 

 

九、

十、总结

  1. TreeMap 实现了 Map 接口,内部节点类型为 Entry;

  2. 基于红黑树实现,具有红黑树的特点;

  3. 有序,根据 Entry 的 key 排序;

  4. 查找、插入、删除操作的时间复杂度均为 O(logn)

 

 

posted on 2021-05-10 13:19  格物致知_Tony  阅读(65)  评论(0编辑  收藏  举报