TreeMap的整体架构

TreeMap 底层的数据结构是红黑树,和 HashMap 的红黑树结构一样。
不同的是,TreeMap 利用了红黑树左节点小,右节点大的性质,根据 key 进行排序,使每个元素能够插入到红黑树大小适当的位置,维护了 key 的大小关系,TreeMap 适用于 key 需要排序的场景。
因为底层的数据结构是红黑树,所以 containsKey()、get()、put()、remove() 等方法的时间复杂度都是 log(n)


TreeMap 的部分底层源码

  1. public class TreeMap<K,V> extends AbstractMap<K,V>
  2. implements NavigableMap<K,V>, Cloneable, java.io.Serializable {
  3. // 用于在 TreeMap 中保持顺序的外部比较器,如果它使用键的自然顺序,则该值为 null
  4. // 如果该值为 null,则使用 key 实现的 Comparable.compareTo()
  5. private final Comparator<? super K> comparator;
  6. // 红黑树的根节点
  7. private transient Entry<K,V> root;
  8. // 红黑树节点的数量
  9. private transient int size = 0;
  10. // 树结构修改的次数
  11. private transient int modCount = 0;
  12. // 使用键的自然顺序构造一个新的空 TreeMap。
  13. // 键的类型必须实现 Comparable 接口
  14. // 所有的键相互比较 k1.compareTo(k2) 必须不抛出 ClassCastException
  15. public TreeMap() {
  16. comparator = null;
  17. }
  18. // 根据给定的外部排序器构造一个新的空 TreeMap
  19. // 所有键相互比较由给定的比较器 comparator.compare(k1, k2) 必须不抛出 ClassCastException
  20. public TreeMap(Comparator<? super K> comparator) {
  21. this.comparator = comparator;
  22. }
  23. // 构造一个包含给定 map 数据的 TreeMap
  24. // 根据键的自然顺序排序
  25. // 键的类型必须实现 Comparable 接口
  26. // 所有的键相互比较 k1.compareTo(k2) 必须不抛出 ClassCastException
  27. // 该方法运行时间为 n*log(n)
  28. public TreeMap(Map<? extends K, ? extends V> m) {
  29. comparator = null;
  30. putAll(m);
  31. }
  32. // 构造一个包含给定 map 数据的 TreeMap,并使用与指定的 SortedMap 相同的顺序
  33. // 该方法在线性时间内运行
  34. public TreeMap(SortedMap<K, ? extends V> m) {
  35. comparator = m.comparator();
  36. try {
  37. buildFromSorted(m.size(), m.entrySet().iterator(), null, null);
  38. } catch (java.io.IOException cannotHappen) {
  39. } catch (ClassNotFoundException cannotHappen) {
  40. }
  41. }
  42. // Red-black mechanics
  43. private static final boolean RED = false;
  44. private static final boolean BLACK = true;
  45. // 红黑树的节点
  46. static final class Entry<K,V> implements Map.Entry<K,V> {
  47. K key;
  48. V value;
  49. Entry<K,V> left;
  50. Entry<K,V> right;
  51. Entry<K,V> parent;
  52. boolean color = BLACK;
  53. Entry(K key, V value, Entry<K,V> parent) {
  54. this.key = key;
  55. this.value = value;
  56. this.parent = parent;
  57. }
  58. public K getKey() {
  59. return key;
  60. }
  61. public V getValue() {
  62. return value;
  63. }
  64. public V setValue(V value) {
  65. V oldValue = this.value;
  66. this.value = value;
  67. return oldValue;
  68. }
  69. public boolean equals(Object o) {
  70. if (!(o instanceof Map.Entry))
  71. return false;
  72. Map.Entry<?,?> e = (Map.Entry<?,?>)o;
  73. return valEquals(key,e.getKey()) && valEquals(value,e.getValue());
  74. }
  75. public int hashCode() {
  76. int keyHash = (key==null ? 0 : key.hashCode());
  77. int valueHash = (value==null ? 0 : value.hashCode());
  78. return keyHash ^ valueHash;
  79. }
  80. public String toString() {
  81. return key + "=" + value;
  82. }
  83. }

TreeMap的新增

TreeMap 新增节点的大概步骤:

  • 判断红黑树的跟节点是否为空,为空的话,新增的节点直接作为根节点
  • 根据红黑树左小右大的特性,进行判断,找到应该新增节点的父节点,或者直接替换旧值
  • 在父节点的左边或右边插入新增节点
  • 着色旋转,达到平衡,结束

put() 的底层源码实现如下:

  1. // 将指定值与此 TreeMap 中的指定键关联。如果之前的 TreeMap 包含键的映射,那么旧的值将被替换
  2. // 返回 key 之前映射的值,如果不存在则返回 null
  3. public V put(K key, V value) {
  4. // 红黑树的根节点
  5. Entry<K,V> t = root;
  6. // 判断红黑树的跟节点是否为空,如果为 null,则新增节点直接作为根节点
  7. if (t == null) {
  8. // 使用该 TreeMap 的正确比较方法比较两个键
  9. // compare 方法限制了 key 不能为 null(但 val 可以为 null)
  10. compare(key, key); // type (and possibly null) check
  11. root = new Entry<>(key, value, null);
  12. size = 1;
  13. modCount++;
  14. return null;
  15. }
  16. //cmp 用于存储每一次节点的 key 对比的结果
  17. int cmp;
  18. // 应该新增节点的父节点
  19. Entry<K,V> parent;
  20. // split comparator and comparable paths
  21. Comparator<? super K> cpr = comparator;
  22. // 如果传入的外部排序器 cpmparator 不为 null,则使用外部排序器
  23. if (cpr != null) {
  24. do {
  25. // 第一次循环时,parent 是红黑树的根节点,一次循环结束时,parent 就是上次比过的对象
  26. parent = t;
  27. cmp = cpr.compare(key, t.key);
  28. // 如果新增节点的 key < 当前节点的 key
  29. if (cmp < 0)
  30. t = t.left;
  31. // 如果新增节点的 key > 当前节点的 key
  32. else if (cmp > 0)
  33. t = t.right;
  34. // 如果新增节点的 key == 当前节点的 key,不用新增节点,直接替换旧值
  35. else
  36. return t.setValue(value);
  37. } while (t != null);
  38. }
  39. // 如果传入的外部排序器 cpmparator 为 null,则使用 key 实现的 Comparable.compareTo()
  40. else {
  41. if (key == null)
  42. throw new NullPointerException();
  43. @SuppressWarnings("unchecked")
  44. Comparable<? super K> k = (Comparable<? super K>) key;
  45. // 这个循环和上面 if 中的循环类似,不做注释说明
  46. do {
  47. parent = t;
  48. cmp = k.compareTo(t.key);
  49. if (cmp < 0)
  50. t = t.left;
  51. else if (cmp > 0)
  52. t = t.right;
  53. else
  54. return t.setValue(value);
  55. } while (t != null);
  56. }
  57. // 构建新增节点
  58. Entry<K,V> e = new Entry<>(key, value, parent);
  59. // 此时 cmp 代表最后一次对比的结果
  60. // 如果 cmp < 0 ,代表节点 e 的 key < 节点 parent 的 key
  61. if (cmp < 0)
  62. // 节点 e 作为节点 parent 的左子节点
  63. parent.left = e;
  64. else
  65. parent.right = e;
  66. // 进行着色旋转操作
  67. fixAfterInsertion(e);
  68. // 红黑树的节点数量 + 1
  69. size++;
  70. // 红黑树的结构的修改次数 + 1
  71. modCount++;
  72. return null;
  73. }
  74. // 使用该 TreeMap 的正确比较方法比较两个键
  75. final int compare(Object k1, Object k2) {
  76. return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2)
  77. : comparator.compare((K)k1, (K)k2);
  78. }
  79. /** From CLR */
  80. // 该方法进行着色旋转操作
  81. private void fixAfterInsertion(Entry<K,V> x) {
  82. x.color = RED;
  83. while (x != null && x != root && x.parent.color == RED) {
  84. if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
  85. Entry<K,V> y = rightOf(parentOf(parentOf(x)));
  86. if (colorOf(y) == RED) {
  87. setColor(parentOf(x), BLACK);
  88. setColor(y, BLACK);
  89. setColor(parentOf(parentOf(x)), RED);
  90. x = parentOf(parentOf(x));
  91. } else {
  92. if (x == rightOf(parentOf(x))) {
  93. x = parentOf(x);
  94. rotateLeft(x);
  95. }
  96. setColor(parentOf(x), BLACK);
  97. setColor(parentOf(parentOf(x)), RED);
  98. rotateRight(parentOf(parentOf(x)));
  99. }
  100. } else {
  101. Entry<K,V> y = leftOf(parentOf(parentOf(x)));
  102. if (colorOf(y) == RED) {
  103. setColor(parentOf(x), BLACK);
  104. setColor(y, BLACK);
  105. setColor(parentOf(parentOf(x)), RED);
  106. x = parentOf(parentOf(x));
  107. } else {
  108. if (x == leftOf(parentOf(x))) {
  109. x = parentOf(x);
  110. rotateRight(x);
  111. }
  112. setColor(parentOf(x), BLACK);
  113. setColor(parentOf(parentOf(x)), RED);
  114. rotateLeft(parentOf(parentOf(x)));
  115. }
  116. }
  117. }
  118. root.color = BLACK;
  119. }

TreeMap的

TreeMap的

TreeMap的