java TreeMap源码解析

Posted StubbornAnt

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java TreeMap源码解析相关的知识,希望对你有一定的参考价值。

TreeMap 概要

  • 基于红黑树的NavigableMap
  • put,get,remove,containsKey操作时间复杂度 log(n)
  • 提供给SortedMap的比较器或者自身的比较函数必须与equals方法一致,因为对于SortedMap,是否相等是基于compare或者compareTo方法的,如果compare方法与equals方法不一致,SortedMap也可以工作,只是与Map接口(是否相等是基于equals方法和hashCode方法的)的put等方法含义不一致
  • 非线程安全的类,可以使用SortedMap m = Collections.synchronizedSortedMap(new TreeMap(...));方法达到线程安全的的目的
  • 该类所产生的所有迭代器都遵循fast-fail机制,迭代器使用过程中,除了迭代器可以对map进行结构性的修改外,其他任何方式的修改都会抛出异常,但是不能依靠这种机制来保证线程安全
  • 不允许null作为键,但可以用null作值

红黑树基础概念

二叉查找树可以用来快速查找,但是由于其不能保证树的平衡性,在最坏的情况查找的效果退化为O(n),红黑树为每个节点添加了颜色存储位,通过添加一些约束条件,确保了任何一个从根到叶子的路径长度不会比其他路径长出2倍,从而确保了树的平衡性

红黑树的性质:

  1. 每个节点是红色或者黑色
  2. 根节点是黑色的
  3. 叶子节点是黑色的
  4. 红色节点的子节点都是黑色的
  5. 当前节点到其后代叶子节点的所有简单路径路的黑色节点数目相同

实现接口

  • TreeMap的Clone方法为浅拷贝,虽然创建了新的Entry,但是是基于原(key,value)对的,并没有创建新的(key,value)
  • TreeMap实现了特殊的序列化机制,对key和value分别写入,在另一端分别读出(key,value),然后将(key,value)对put进map的方法进行反序列化
  • NavigableMap接口主要方法
    • map 接口方法 put,get,remove,contains,keyset,values
    • sortedmap 接口方法 submap,headmap,tailmap,firstKey,lastKey,重写的keySet
    • NavigableMap 接口方法 floormap,ceilingmap,highermap,pollFirstEntry,navigableKeySet
public class TreeMap<K,V>
    extends AbstractMap<K,V>
    implements NavigableMap<K,V>, Cloneable, java.io.Serializable  

public interface NavigableMap<K, V> extends SortedMap<K, V> 
    Map.Entry<K, V> lowerEntry(K key);
    K lowerKey(K key);
    Map.Entry<K, V> floorEntry(K key);
    K floorKey(K key);
    Map.Entry<K, V> ceilingEntry(K key);
    K ceilingKey(K key);
    Map.Entry<K, V> higherEntry(K key);
    K higherKey(K key);
    Map.Entry<K, V> firstEntry();
    Map.Entry<K, V> lastEntry();
    Map.Entry<K, V> pollFirstEntry();
    Map.Entry<K, V> pollLastEntry();
    NavigableMap<K, V> descendingMap();
    NavigableSet<K> navigableKeySet();
    NavigableSet<K> descendingKeySet();
    NavigableMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive);
    NavigableMap<K, V> headMap(K toKey, boolean inclusive);
    NavigableMap<K, V> tailMap(K fromKey, boolean inclusive);
    SortedMap<K, V> subMap(K fromKey, K toKey);
    SortedMap<K, V> headMap(K toKey);
    SortedMap<K, V> tailMap(K fromKey);
  
public interface SortedMap<K, V> extends Map<K, V> 
    Comparator<? super K> comparator();
    SortedMap<K, V> subMap(K fromKey, K toKey);
    SortedMap<K, V> headMap(K toKey);
    SortedMap<K, V> tailMap(K fromKey);
    K firstKey();
    K lastKey();
    Set<K> keySet();
    Collection<V> values();
    Set<Map.Entry<K, V>> entrySet();
 
 public interface Map<K, V> 
    // Query Operations
    int size();
    boolean isEmpty();
    boolean containsKey(Object key);
    boolean containsValue(Object value);
    V get(Object key);
    // Modification Operations
    V put(K key, V value);
    V remove(Object key);
    // Bulk Operations
    void putAll(Map<? extends K, ? extends V> m);
    void clear();
    // Views
    Set<K> keySet();
    Collection<V> values();
    Set<Map.Entry<K, V>> entrySet();
    interface Entry<K, V> 
        K getKey();
        V getValue();
        V setValue(V value);
        boolean equals(Object o);
        int hashCode();
    
    // Comparison and hashing
    boolean equals(Object o);
    int hashCode();

相关成员

  • 比较器用来排序,如果没有提供,且Key实现了Comparable接口,就用Key的compareTo方法
  • root为红黑树的根节点
  • size保存map的元素个数
  • modCount用来实现fail-fast机制
    private final Comparator<? super K> comparator;
    private transient Entry<K,V> root = null;
    private transient int size = 0;
    private transient int modCount = 0;

基本节点

  • 节点包含key,value,左右孩子,以及父节点引用,color默认为BLACK,采用Boolean值表示红黑树的颜色,而不是枚举类型
  • 当key和value的equals方法都返回true时判断Entry为相等
  • hashCode返回key与value的hashcode的按位异或结果
    static final class Entry<K,V> implements Map.Entry<K,V> 
        K key;
        V value;
        Entry<K,V> left = null;
        Entry<K,V> right = null;
        Entry<K,V> parent;
        boolean color = BLACK;

        Entry(K key, V value, Entry<K,V> parent) 
            this.key = key;
            this.value = value;
            this.parent = parent;
        
                // 省略get,set方法
        public boolean equals(Object o) 
            if (!(o instanceof Map.Entry))
                return false;
            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
            return valEquals(key,e.getKey()) && valEquals(value,e.getValue());
        
        public int hashCode() 
            int keyHash = (key==null ? 0 : key.hashCode());
            int valueHash = (value==null ? 0 : value.hashCode());
            return keyHash ^ valueHash;
        
        public String toString() 
            return key + "=" + value;
        
      
    static final boolean valEquals(Object o1, Object o2) 
        return (o1==null ? o2==null : o1.equals(o2));
      

构造方法

  • 没有提供比较器就用ComparableKey的CompareTo
  • 比较器用来对key进行比较
  • 如果提供的map的类型不是SortedMap那么就用put方法逐一添加进去
  • 如果提供的map是排好序的,采用中序遍历的方法重新构建map
    具体算法,首先将整个map平分为左右两部分,左面左子树,右面右子树,中间节点作为根节点,这样构建的树初始是平衡的,构建过程中不需要调整。其中只有最后一个完整的层会被赋值为红色,其他都是黑色,这样有利于后续的插入操作
    public TreeMap() 
        comparator = null;
    
    public TreeMap(Comparator<? super K> comparator) 
        this.comparator = comparator;
    
    public TreeMap(Map<? extends K, ? extends V> m) 
        comparator = null;
        putAll(m);
    
    public void putAll(Map<? extends K, ? extends V> map) 
        int mapSize = map.size();
        if (size==0 && mapSize!=0 && map instanceof SortedMap) 
            Comparator c = ((SortedMap)map).comparator();
            if (c == comparator || (c != null && c.equals(comparator))) 
                ++modCount;
                try 
                    buildFromSorted(mapSize, map.entrySet().iterator(),
                                    null, null);
                 catch (java.io.IOException cannotHappen) 
                 catch (ClassNotFoundException cannotHappen) 
                
                return;
            
        
        super.putAll(map);
      
    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) 
        
      
    private void buildFromSorted(int size, Iterator it,
                                 java.io.ObjectInputStream str,
                                 V defaultVal)
        throws  java.io.IOException, ClassNotFoundException 
        this.size = size;
        root = buildFromSorted(0, 0, size-1, computeRedLevel(size),
                               it, str, defaultVal);
      
    private void buildFromSorted(int size, Iterator it,
                                 java.io.ObjectInputStream str,
                                 V defaultVal)
        throws  java.io.IOException, ClassNotFoundException 
        this.size = size;
        root = buildFromSorted(0, 0, size-1, computeRedLevel(size),
                               it, str, defaultVal);
      
    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) >>> 1;
        Entry<K,V> left  = null;
        if (lo < mid)
            left = buildFromSorted(level+1, lo, mid - 1, redLevel,
                                   it, str, defaultVal);
        // extract key and/or value from iterator or stream
        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());
        
        Entry<K,V> middle =  new Entry<>(key, value, null);
        // color nodes in non-full bottommost level red
        if (level == redLevel)
            middle.color = RED;
        if (left != null) 
            middle.left = left;
            left.parent = middle;
        
        if (mid < hi) 
            Entry<K,V> right = buildFromSorted(level+1, mid+1, hi, redLevel,
                                               it, str, defaultVal);
            middle.right = right;
            right.parent = middle;
        
        return middle;
      
    private static int computeRedLevel(int sz) 
        int level = 0;
        for (int m = sz - 1; m >= 0; m = m / 2 - 1)
            level++;
        return level;
      

查询操作

键查找 containsKey

二叉查找树的查找算法:如果key大于当前节点就去右子树,小于当前节点键值跳到左子树,否则返回当前节点,时间复杂度O(logn)

    public V get(Object key) 
        Entry<K,V> p = getEntry(key);
        return (p==null ? null : p.value);
      
    public boolean containsKey(Object key) 
        return getEntry(key) != null;
     
    final Entry<K,V> getEntry(Object key) 
        // Offload comparator-based version for sake of performance
        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;
     

值查找 containsValue

  • value查找是从第一个节点按顺序逐个查找后继节点对比,时间复杂度O(n)
  • 第一个节点即树的最左端节点
  • 后续节点即大于当前节点的紧邻的下一个节点
    • 如果存在右子树,后继节点为右子树的最左端节点
    • 如果不存在右子树,后继节点为向上回溯过程中,第一个作为其父节点的左子树的节点的父节点
    public boolean containsValue(Object value) 
        for (Entry<K,V> e = getFirstEntry(); e != null; e = successor(e))
            if (valEquals(value, e.value))
                return true;
        return false;
     
    final Entry<K,V> getFirstEntry() 
        Entry<K,V> p = root;
        if (p != null)
            while (p.left != null)
                p = p.left;
        return p;
    
    static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) 
        if (t == null)
            return null;
        else if (t.right != null) 
            Entry<K,V> p = t.right;
            while (p.left != null)
                p = p.left;
            return p;
         else 
            Entry<K,V> p = t.parent;
            Entry<K,V> ch = t;
            while (p != null && ch == p.right) 
                ch = p;
                p = p.parent;
            
            return p;
        
     

元素增删

树的左右旋转

  • 树的旋转可以用来调整树的形状,调整左右子树高度,从而达到树更加平衡的目的
  • 左旋过程,以x为轴
    • 首先保存x的右孩子 y
    • y的左孩子作为x的右孩子
    • y替换原来x的位置(连接到x的父节点)
    • x作为y的左孩子
  • 右旋过程类似左旋
    private void rotateLeft(Entry<K,V> p) 
        if (p != null) 
            Entry<K,V> r = p.right;
            p.right = r.left;
            if (r.left != null)
                r.left.parent = p;
            r.parent = p.parent;
            if (p.parent == null)
                root = r;
            else if (p.parent.left == p)
                p.parent.left = r;
            else
                p.parent.right = r;
            r.left = p;
            p.parent = r;
        
    
    private void rotateRight(Entry<K,V> p) 
        if (p != null) 
            Entry<K,V> l = p.left;
            p.left = l.right;
            if (l.right != null) l.right.parent = p;
            l.parent = p.parent;
            if (p.parent == null)
                root = l;
            else if (p.parent.right == p)
                p.parent.right = l;
            else p.parent.left = l;
            l.right = p;
            p.parent = l;
        
      

添加更新元素 put

  • 首先根据是否提供了比较器(comparator)来区别进行查找
  • 如果找到相等的key(注意这里不是通过equals方法,而是compare方法,所以只有保证compare与equals方法一致,才能保证TreeMap的插入操作与Map接口的定义一致),更新对应节点的value
  • 如果没有找到就新建Entry,然后根据最后一次比较结果作为查找路径的最后节点的左子树或者右子树
  • 新插入节点可能破坏红黑树性质4与性质2,需要进行调整,且调整过程中保证不会破坏其他性质
    • 首先当前插入节点为红色
    • 如果其父节点也是红色,进行调整
    • 直到性质4不再被违背后将根节点图为黑色,性质2满足,结束调整

父节点为红色时需要进行调整,调整分为三种情况,叔节点为x的parent的parent的另一个孩子,其中x节点的父节点为祖父节点的左右子树的情况与左子树的情况是对称的
- 情况一,如果x的叔节点为红色,就把父节点与叔节点都染黑,祖父节点染红,x跳转到祖父节点继续调整
- 情况二,如果叔节点是黑色的,且当前节点为其父节点的右孩子,就以其父节点为轴进行左旋,结果跳转到情况三
- 情况三,如果叔节点是黑色的,且当前节点为其父节点的左孩子,先将父节点染黑,祖父节点染红,然后进行右旋

    public V put(K key, V value) 
        Entry<K,V> t = root;
        if (t == null) 
            compare(key, key); // type (and possibly null) check
            root = new Entry<>(key, value, null);
            size = 1;
            modCount++;
            return null;
        
        int cmp;
        Entry<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();
            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;
      
    private void fixAfterInsertion(Entry<K,V> x) 
        x.color = RED;
        while (x != null && x != root && x.parent.color == RED) 
            if (parentOf(x) == leftOf(parentOf(parentOf(x)))) 
                Entry<K,V> y = rightOf(parentOf(parentOf(x)));
                if (colorOf(y) == RED) 
                    setColor(parentOf(x), BLACK);
                    setColor(y, BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    x = parentOf(parentOf(x));
                 else 
                    if (x == rightOf(parentOf(x))) 
                        x = parentOf(x);
                        rotateLeft(x);
                    
                    setColor(parentOf(x), BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    rotateRight(parentOf(parentOf(x)));
                
             else 
                Entry<K,V> y = leftOf(parentOf(parentOf(x)));
                if (colorOf(y) == RED) 
                    setColor(parentOf(x), BLACK);
                    setColor(y, BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    x = parentOf(parentOf(x));
                 else 
                    if (x == leftOf(parentOf(x))) 
                        x = parentOf(x);
                        rotateRight(x);
                    
                    setColor(parentOf(x), BLACK);
                    setColor(parentOf(parentOf(x)), RED);
                    rotateLeft(parentOf(parentOf(x)));
                
            
        
        root.color = BLACK;
      

删除元素 remove

首先查找到指定元素,进行删除

  • 首先查找要删除的元素,大于右树,小于左树,如果没找到返回null
  • 执行删除节点x的操作,分三种情况
    • 如果x没有左孩子,或者没有右孩子,那么就用其右子树或者左子树替换当前节点x
    • 如果x既有左孩子又有右孩子,且右孩子没有左子树(也就是右孩子为当前节点后继节点),就用其右孩子替换当前节点,并将原左子树作为其左子树
    • 如果x既有左孩子又有右孩子,且右孩子有左子树,那么首先找到节点x的后继节点y,由于y满足第一种情况(没有左孩子),所以用y的右孩子替换y,然后用y替换当前节点x

如果删除元素是黑色的,可能会破坏原有的红黑树的性质,所以删除后需要进行调整,x节点是其父节点的左右孩子的情况对称,每种情况分四种情况

  • 如果兄弟节点是红色的(其父节点一定是黑色的,因为根据红黑树性质红色节点的孩子一定是黑色的),将其兄弟节点染黑,并将其父节点染红,然后以其父节点为轴进行左旋,旋转后原兄弟节点的左孩子成为x新的兄弟节点
  • 如果兄弟节点是黑色的且其左右子树都是黑色的(第一种情况旋转后必然到第二种情况),将其兄弟节点染为红色,x跳到其父节点(只需要最后再将x染红,调整结束)
  • 如果兄弟节点是黑色的且其右子树是黑色的左子树为红色,将其兄弟节点左子树染为黑色,其兄弟节点染为红色,以其兄弟节点为轴执行右旋(执行完跳转到下一种情况)
  • 如果兄弟节点是黑色的且其右子树是红色的,兄弟节点染为其父亲节点颜色,父节点染为黑色,兄弟节点右孩子染为黑色,以其父节点为轴左旋,x跳转到根节点
    public V remove(Object key) 
        Entry<K,V> p = getEntry(key);
        if (p == null)
            return null;
        V oldValue = p.value;
        deleteEntry(p);
        return oldValue;
     
    private void deleteEntry(Entry<K,V> p) 
        modCount++;
        size--;
        // If strictly internal, copy successor's element to p and then make p
        // point to successor.
        if (p.left != null && p.right != null) 
            Entry<K,V> s = successor(p);
            p.key = s.key;
            p.value = s.value;
            p = s;
         // p has 2 children
        // Start fixup at replacement node, if it exists.
        Entry<K,V> replacement = (p.left != null ? p.left : p.right);
        if (replacement != null) 
            // Link replacement to parent
            replacement.parent = p.parent;
            if (p.parent == null)
                root = replacement;
            else if (p == p.parent.left)
                p.parent.left  = replacement;
            else
                p.parent.right = replacement;
            // Null out links so they are OK to use by fixAfterDeletion.
            p.left = p.right = p.parent = null;
            // Fix replacement
            if (p.color == BLACK)
                fixAfterDeletion(replacement);
         else if (p.parent == null)  // return if we are the only node.
            root = null;
         else  //  No children. Use self as phantom replacement and unlink.
            if (p.color == BLACK)
                fixAfterDeletion(p);
            if (p.parent != null) 
                if (p == p.parent.left)
                    p.parent.left = null;
                else if (p == p.parent.right)
                    p.parent.right = null;
                p.parent = null;
            
        
    
    /** From CLR */
    private void fixAfterDeletion(Entry<K,V> x) 
        while (x != root && colorOf(x) == BLACK) 
            if (x == leftOf(parentOf(x))) 
                Entry<K,V> sib = rightOf(parentOf(x));
                if (colorOf(sib) == RED) 
                    setColor(sib, BLACK);
                    setColor(parentOf(x), RED);
                    rotateLeft(parentOf(x));
                    sib = rightOf(parentOf(x));
                
                if (colorOf(leftOf(sib))  == BLACK &&
                    colorOf(rightOf(sib)) == BLACK) 
                    setColor(sib, RED);
                    x = parentOf(x);
                 else 
                    if (colorOf(rightOf(sib)) == BLACK) 
                        setColor(leftOf(sib), BLACK);
                        setColor(sib, RED);
                        rotateRight(sib);
                        sib = rightOf(parentOf(x));
                    
                    setColor(sib, colorOf(parentOf(x)));
                    setColor(parentOf(x), BLACK);
                    setColor(rightOf(sib), BLACK);
                    rotateLeft(parentOf(x));
                    x = root;
                
             else  // symmetric
                Entry<K,V> sib = leftOf(parentOf(x));
                if (colorOf(sib) == RED) 
                    setColor(sib, BLACK);
                    setColor(parentOf(x), RED);
                    rotateRight(parentOf(x));
                    sib = leftOf(parentOf(x));
                
                if (colorOf(rightOf(sib)) == BLACK &&
                    colorOf(leftOf(sib)) == BLACK) 
                    setColor(sib, RED);
                    x = parentOf(x);
                 else 
                    if (colorOf(leftOf(sib)) == BLACK) 
                        setColor(rightOf(sib), BLACK);
                        setColor(sib, RED);
                        rotateLeft(sib);
                        sib = leftOf(parentOf(x));
                    
                    setColor(sib, colorOf(parentOf(x)));
                    setColor(parentOf(x), BLACK);
                    setColor(leftOf(sib), BLACK);
                    rotateRight(parentOf(x));
                    x = root;
                
            
        
        setColor(x, BLACK);
     

清空元素

直接将根节点置为null,清空元素

    public void clear() 
        modCount++;
        size = 0;
        root = null;
      

浅拷贝 clone

  • 克隆方法是用递归的方法从有序序列中以中序遍历构建红黑色的过程
  • 虽然重建map过程中新建了Entry,但是并没有执行key,value的克隆,所以是浅拷贝,也就是原map更新了key或value对象属性,新map中key,value对象也会对应的改变
    public Object clone() 
        TreeMap<K,V> clone = null;
        try 
            clone = (TreeMap<K,V>) super.clone();
         catch (CloneNotSupportedException e) 
            throw new InternalError();
        
        // Put clone into "virgin" state (except for comparator)
        clone.root = null;
        clone.size = 0;
        clone.modCount = 0;
        clone.entrySet = null;
        clone.navigableKeySet = null;
        clone.descendingMap = null;
        // Initialize clone with our mappings
        try 
            clone.buildFromSorted(size, entrySet().iterator(), null, null);
         catch (java.io.IOException cannotHappen) 
         catch (ClassNotFoundException cannotHappen) 
        
        return clone;
     
    private void buildFromSorted(int size, Iterator it,
                                 java.io.ObjectInputStream str,
                                 V defaultVal)
        throws  java.io.IOException, ClassNotFoundException 
        this.size = size;
        root = buildFromSorted(0, 0, size-1, computeRedLevel(size),
                               it, str, defaultVal);
    
    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) >>> 1;
        Entry<K,V> left  = null;
        if (lo < mid)
            left = buildFromSorted(level+1, lo, mid - 1, redLevel,
                                   it, str, defaultVal);
        // extract key and/or value from iterator or stream
        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());
        
        Entry<K,V> middle =  new Entry<>(key, value, null);
        // color nodes in non-full bottommost level red
        if (level == redLevel)
            middle.color = RED;
        if (left != null) 
            middle.left = left;
            left.parent = middle;
        
        if (mid < hi) 
            Entry<K,V> right = buildFromSorted(level+1, mid+1, hi, redLevel,
                                               it, str, defaultVal);
            middle.right = right;
            right.parent = middle;
        
        return middle;
     

方法总览

在按导航访问map元素时返回的并不是原Map中的Entry,而是新建了一个不可变的Entry,Entry的不可变属性通过让其setValue方法直接抛出异常来实现

    public Map.Entry<K,V> firstEntry() 
        return exportEntry(getFirstEntry());
    

    public Map.Entry<K,V> lastEntry() 
        return exportEntry(getLastEntry());
    

    public Map.Entry<K,V> pollFirstEntry() 
        Entry<K,V> p = getFirstEntry();
        Map.Entry<K,V> result = exportEntry(p);
        if (p != null)
            deleteEntry(p);
        return result;
    

    public Map.Entry<K,V> pollLastEntry() 
        Entry<K,V> p = getLastEntry();
        Map.Entry<K,V> result = exportEntry(p);
        if (p != null)
            deleteEntry(p);
        return result;
    

    public Map.Entry<K,V> lowerEntry(K key) 
        return exportEntry(getLowerEntry(key));
    

    public Map.Entry<K,V> floorEntry(K key) 
        return exportEntry(getFloorEntry(key));
    

    public Map.Entry<K,V> ceilingEntry(K key) 
        return exportEntry(getCeilingEntry(key));
     

    public Map.Entry<K,V> higherEntry(K key) 
        return exportEntry(getHigherEntry(key));
     

    static <K,V> Map.Entry<K,V> exportEntry(TreeMap.Entry<K,V> e) 
        return (e == null) ? null :
            new AbstractMap.SimpleImmutableEntry<>(e);
      

   public static class SimpleImmutableEntry<K,V>
        implements Entry<K,V>, java.io.Serializable
    
        private final K key;
        private final V value;
        public SimpleImmutableEntry(Entry<? extends K, ? extends V> entry) 
            this.key   = entry.getKey();
            this.value = entry.getValue();
        

        public V setValue(V value) 
            throw new UnsupportedOperationException();
        
        //省略其他方法
      

查找头尾节点

  • 第一个节点为树最左侧节点
  • 最后一个节点为树最右侧节点
    final Entry<K,V> getFirstEntry() 
        Entry<K,V> p = root;
        if (p != null)
            while (p.left != null)
                p = p.left;
        return p;
    
    final Entry<K,V> getLastEntry() 
        Entry<K,V> p = root;
        if (p != null)
            while (p.right != null)
                p = p.right;
        return p;
      

前驱与后继

  • 前驱节点
    • 如果存在左子树,前驱节点为左子树最右端节点
    • 如果不存在左子树,前驱节点为,向上回溯过程中第一个作为其父节点的右子树的节点的父节点
  • 后继节点
    • 如果存在右子树,后继节点为右子树最左端节点
    • 如果不存在右子树,后继节点为向上回溯过程中,第一个作为其父节点的左子树的节点的父节点
    static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) 
        if (t == null)
            return null;
        else if (t.right != null) 
            Entry<K,V> p = t.right;
            while (p.left != null)
                p = p.left;
            return p;
         else 
            Entry<K,V> p = t.parent;
            Entry<K,V> ch = t;
            while (p != null && ch == p.right) 
                ch = p;
                p = p.parent;
            
            return p;
        
    
    static <K,V> Entry<K,V> predecessor(Entry<K,V> t) 
        if (t == null)
            return null;
        else if (t.left != null) 
            Entry<K,V> p = t.left;
            while (p.right != null)
                p = p.right;
            return p;
         else 
            Entry<K,V> p = t.parent;
            Entry<K,V> ch = t;
            while (p != null && ch == p.left) 
                ch = p;
                p = p.parent;
            
            return p;
        
      

不大于当前值的最大值(ceiling) 不小于当前值的最小值(floor)

  • 如果找到相等的节点就直接返回
  • 如果没有找到,且最后一个遍历的节点为p
    • ceiling 如果最后一次比p小,那么p就是ceiling节点,否则为p的后继节点
    • floor 如果最后一次比p大,那么p就是floor节点,否则为p的前驱节点
    final Entry<K,V> getCeilingEntry(K key) 
        Entry<K,V> p = root;
        while (p != null) 
            int cmp = compare(key, p.key);
            if (cmp < 0) 
                if (p.left != null)
                    p = p.left;
                else
                    return p;
             else if (cmp > 0) 
                if (p.right != null) 
                    p = p.right;
                 else 
                    Entry<K,V> parent = p.parent;
                    Entry<K,V> ch = p;
                    while (parent != null && ch == parent.right) 
                        ch = parent;
                        parent = parent.parent;
                    
                    return parent;
                
             else
                return p;
        
        return null;
    
    final Entry<K,V> getFloorEntry(K key) 
        Entry<K,V> p = root;
        while (p != null) 
            int cmp = compare(key, p.key);
            if (cmp > 0) 
                if (p.right != null)
                    p = p.right;
                else
                    return p;
             else if (cmp < 0) 
                if (p.left != null) 
                    p = p.left;
                 else 
                    Entry<K,V> parent = p.parent;
                    Entry<K,V> ch = p;
                    while (parent != null && ch == parent.left) 
                        ch = parent;
                        parent = parent.parent;
                    
                    return parent;
                
             else
                return p;
        
        return null;
      

下一个节点(higher) 上一个节点 (lower)

  • higher节点与floor基本一样,唯一的区别在于floor为大于等于,higher为大于,反映到算法上为查找higher时与当前节点equals,跳转到右子树上,而floor节点直接返回p
  • lower节点与ceiling节点一样,区别同上
    final Entry<K,V> getHigherEntry(K key) 
        Entry<K,V> p = root;
        while (p != null) 
            int cmp = compare(key, p.key);
            if (cmp < 0) 
                if (p.left != null)
                    p = p.left;
                else
                    return p;
             else 
                if (p.right != null) 
                    p = p.right;
                 else 
                    Entry<K,V> parent = p.parent;
                    Entry<K,V> ch = p;
                    while (parent != null && ch == parent.right) 
                        ch = parent;
                        parent = parent.parent;
                    
                    return parent;
                
            
        
        return null;
      
    final Entry<K,V> getLowerEntry(K key) 
        Entry<K,V> p = root;
        while (p != null) 
            int cmp = compare(key, p.key);
            if (cmp > 0) 
                if (p.right != null)
                    p = p.right;
                else
                    return p;
             else 
                if (p.left != null) 
                    p = p.left;
                 else 
                    Entry<K,V> parent = p.parent;
                    Entry<K,V> ch = p;
                    while (parent != null && ch == parent.left) 
                        ch = parent;
                        parent = parent.parent;
                    
                    return parent;
                
            
        
        return null;
      

Java - TreeSet源码解析

java TreeMap源码解析

#yyds干货盘点# Map - TreeSet & TreeMap 源码解析

Java - HashTree源码解析 + 红黑树

TreeMap关键源码解析-红黑树操作

死磕 java集合之TreeMap源码分析- 内含红黑树分析全过程