HashMap中树的相关操作

1.数据模型

    /**
     * hashMap超长时的数据模型,红黑树
     * 并且在树中维护了一个潜在的双向链表(原链表的关系)
     */
    static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
    
    
        TreeNode<K,V> parent;  // red-black tree links
        TreeNode<K,V> left;
        TreeNode<K,V> right;
        TreeNode<K,V> prev;    // needed to unlink next upon deletion
        boolean red;
        TreeNode(int hash, K key, V val, Node<K,V> next) {
    
    
            super(hash, key, val, next);
        }
    }

2.查找根节点

        /**
         * 返回此树的根节点,根节点为null
         */
        final TreeNode<K,V> root() {
    
    
            for (TreeNode<K,V> r = this, p;;) {
    
    
                if ((p = r.parent) == null)
                    return r;
                r = p;
            }
        }

3. 树节点查找

        /**
         * 红黑树,左小右大
         * 1. 按hash转到左子树或右子树,左小右大
         * 2. 如果hash相同,key相同
         * 3. 如果当前节点有左或右为null,直接转到另一侧
         * 4. hash相同,如果key不同,k.class实现comparable接口,并且当前节点.class和key.class相同类不同大小,左小右大
         * 5. hash相同,如果key不同,k.class没实现comparable接口,或者当前节点.class和key.class不同类,转到右子树,
         * 5. hash相同,如果key不同,k.class没实现comparable接口,或者当前节点.class和key.class不同类,右子树没有该值,遍历左子树
         */
        final TreeNode<K,V> find(int h, Object k, Class<?> kc) {
    
    
            TreeNode<K,V> p = this;
            do {
    
    
                int ph, dir; K pk;
                TreeNode<K,V> pl = p.left, pr = p.right, q;
                if ((ph = p.hash) > h)
                    p = pl;
                else if (ph < h)
                    p = pr;
                else if ((pk = p.key) == k || (k != null && k.equals(pk)))
                    return p;
                else if (pl == null)
                    p = pr;
                else if (pr == null)
                    p = pl;
                else if ((kc != null ||
                        (kc = comparableClassFor(k)) != null) &&
                        (dir = compareComparables(kc, k, pk)) != 0)
                    p = (dir < 0) ? pl : pr;
                else if ((q = pr.find(h, k, kc)) != null)
                    return q;
                else
                    p = pl;
            } while (p != null);
            return null;
        }

4. hash索引相同时比较大小

        /**
         * ab不同类比较ab类名
         * ab同类比较hashCode,相等判定b大
         */
        static int tieBreakOrder(Object a, Object b) {
    
    
            int d;
            if (a == null || b == null ||
                    (d = a.getClass().getName().
                            compareTo(b.getClass().getName())) == 0)
                d = (System.identityHashCode(a) <= System.identityHashCode(b) ?
                        -1 : 1);
            return d;
        }

5.链表转为树

        /**
         * 将链表转为树
         * 1. 第一个节点设为root
         * 2. 左小右大,成功插入平衡一次
         * 3. 根节点调整为潜在链表的首节点
         */
        final void treeify(Node<K,V>[] tab) {
    
    
            TreeNode<K,V> root = null;
            for (TreeNode<K,V> x = this, next; x != null; x = next) {
    
    
                next = (TreeNode<K,V>)x.next;
                x.left = x.right = null;
                if (root == null) {
    
    
                    x.parent = null;
                    x.red = false;
                    root = x;
                }
                else {
    
    
                    K k = x.key;
                    int h = x.hash;
                    Class<?> kc = null;
                    for (TreeNode<K,V> p = root;;) {
    
    
                        int dir, ph;
                        K pk = p.key;
                        if ((ph = p.hash) > h)
                            dir = -1;
                        else if (ph < h)
                            dir = 1;
                        else if ((kc == null &&
                                (kc = comparableClassFor(k)) == null) ||
                                (dir = compareComparables(kc, k, pk)) == 0)
                            dir = tieBreakOrder(k, pk);

                        TreeNode<K,V> xp = p;
                        if ((p = (dir <= 0) ? p.left : p.right) == null) {
    
    
                            x.parent = xp;
                            if (dir <= 0)
                                xp.left = x;
                            else
                                xp.right = x;
                            root = balanceInsertion(root, x);
                            break;
                        }
                    }
                }
            }
            moveRootToFront(tab, root);
        }

6. 树put节点方法

        /**
         * 树结构的putVal
         * 1. 拿到当前树的根节点,判断k要在跟节点的左边还是右边dir<=0放左边
         * 2. 如果根节点与新增的节点hash,key相同直接返回
         * 3. 如果hash值相同,key值不同,并且不能比较key的大小
         *  1)分别遍历左子树右子树,如果找到key节点return(此步骤只会执行一次,如果没有,说明没有该节点)
         *  2)判断要插入的k和当前hash值相同key的大小,如果相等,也是pk大(即使相等也放左边)
         * 4. 插入好位置处创建节点,并维护好双向链表的访问顺序
         * 5. 插入后平衡红黑树
         */
        final TreeNode<K,V> putTreeVal(HashMap<K,V> map, Node<K,V>[] tab,
                                       int h, K k, V v) {
    
    
            Class<?> kc = null;
            boolean searched = false;
            TreeNode<K,V> root = (parent != null) ? root() : this;
            for (TreeNode<K,V> p = root;;) {
    
    
                int dir, ph; K pk;
                if ((ph = p.hash) > h)
                    dir = -1;
                else if (ph < h)
                    dir = 1;
                else if ((pk = p.key) == k || (k != null && k.equals(pk)))
                    return p;
                else if ((kc == null &&
                        (kc = comparableClassFor(k)) == null) ||
                        (dir = compareComparables(kc, k, pk)) == 0) {
    
    
                    if (!searched) {
    
    
                        TreeNode<K,V> q, ch;
                        searched = true;
                        if (((ch = p.left) != null &&
                                (q = ch.find(h, k, kc)) != null) ||
                                ((ch = p.right) != null &&
                                        (q = ch.find(h, k, kc)) != null))
                            return q;
                    }
                    dir = tieBreakOrder(k, pk);
                }

                TreeNode<K,V> xp = p;
                if ((p = (dir <= 0) ? p.left : p.right) == null) {
    
    
                    Node<K,V> xpn = xp.next;
                    TreeNode<K,V> x = map.newTreeNode(h, k, v, xpn);
                    if (dir <= 0)
                        xp.left = x;
                    else
                        xp.right = x;
                    xp.next = x;
                    x.parent = x.prev = xp;
                    if (xpn != null)
                        ((TreeNode<K,V>)xpn).prev = x;
                    moveRootToFront(tab, balanceInsertion(root, x));
                    return null;
                }
            }
        }

7.树删除节点操作

        /**
         * 删除树节点
         * 1. 链表层面进行删除
         * 2. 如果平衡的红黑树剩余节点满足结构(树结构)调用untreeify将树转为链表
         * 3. 删除节点平衡树
         */
        final void removeTreeNode(HashMap<K,V> map, Node<K,V>[] tab,
                                  boolean movable) {
    
    
            int n;
            if (tab == null || (n = tab.length) == 0)
                return;
            int index = (n - 1) & hash;
            TreeNode<K,V> first = (TreeNode<K,V>)tab[index], root = first, rl;
            TreeNode<K,V> succ = (TreeNode<K,V>)next, pred = prev;
            if (pred == null)
                tab[index] = first = succ;
            else
                pred.next = succ;
            if (succ != null)
                succ.prev = pred;
            if (first == null)
                return;
            if (root.parent != null)
                root = root.root();
            if (root == null
                    || (movable
                    && (root.right == null
                    || (rl = root.left) == null
                    || rl.left == null))) {
    
    
                tab[index] = first.untreeify(map);  // too small
                return;
            }
            TreeNode<K,V> p = this, pl = left, pr = right, replacement;
            if (pl != null && pr != null) {
    
    
                TreeNode<K,V> s = pr, sl;
                while ((sl = s.left) != null) // find successor
                    s = sl;
                boolean c = s.red; s.red = p.red; p.red = c; // swap colors
                TreeNode<K,V> sr = s.right;
                TreeNode<K,V> pp = p.parent;
                if (s == pr) {
    
     // p was s's direct parent
                    p.parent = s;
                    s.right = p;
                }
                else {
    
    
                    TreeNode<K,V> sp = s.parent;
                    if ((p.parent = sp) != null) {
    
    
                        if (s == sp.left)
                            sp.left = p;
                        else
                            sp.right = p;
                    }
                    if ((s.right = pr) != null)
                        pr.parent = s;
                }
                p.left = null;
                if ((p.right = sr) != null)
                    sr.parent = p;
                if ((s.left = pl) != null)
                    pl.parent = s;
                if ((s.parent = pp) == null)
                    root = s;
                else if (p == pp.left)
                    pp.left = s;
                else
                    pp.right = s;
                if (sr != null)
                    replacement = sr;
                else
                    replacement = p;
            }
            else if (pl != null)
                replacement = pl;
            else if (pr != null)
                replacement = pr;
            else
                replacement = p;
            if (replacement != p) {
    
    
                TreeNode<K,V> pp = replacement.parent = p.parent;
                if (pp == null)
                    root = replacement;
                else if (p == pp.left)
                    pp.left = replacement;
                else
                    pp.right = replacement;
                p.left = p.right = p.parent = null;
            }

            TreeNode<K,V> r = p.red ? root : balanceDeletion(root, replacement);

            if (replacement == p) {
    
      // detach
                TreeNode<K,V> pp = p.parent;
                p.parent = null;
                if (pp != null) {
    
    
                    if (p == pp.left)
                        pp.left = null;
                    else if (p == pp.right)
                        pp.right = null;
                }
            }
            if (movable)
                moveRootToFront(tab, r);
        }

8.扩容时,分散相同hash索引方法

        /**
         * 此方法专为resize使用
         * 1. 链表的形式遍历树
         * 2. 拿到的节点按位与之前的数组长度
         * 计算hash索引使用table.length -1与hash值&,如00000000000000000000000000001111&00000000000000000000000000011111得到00000000000000000000000000001111
         *  table的扩展方式为左移一位,现在换成00000000000000000000000000011111&00000000000000000000000000011111得到00000000000000000000000000011111
         *  所以扩充大小后的hash索引是否改变,关键在于00000000000000000000000000010000,“1”位,如果是相与结果是0,不需要修改hash索引
         * 3. 判断拆开后的两个链表如果<=6,把树改为链表
         */
        final void split(HashMap<K,V> map, Node<K,V>[] tab, int index, int bit) {
    
    
            TreeNode<K,V> b = this;
            // Relink into lo and hi lists, preserving order
            TreeNode<K,V> loHead = null, loTail = null;
            TreeNode<K,V> hiHead = null, hiTail = null;
            int lc = 0, hc = 0;
            for (TreeNode<K,V> e = b, next; e != null; e = next) {
    
    
                next = (TreeNode<K,V>)e.next;
                e.next = null;
                if ((e.hash & bit) == 0) {
    
    
                    if ((e.prev = loTail) == null)
                        loHead = e;
                    else
                        loTail.next = e;
                    loTail = e;
                    ++lc;
                }
                else {
    
    
                    if ((e.prev = hiTail) == null)
                        hiHead = e;
                    else
                        hiTail.next = e;
                    hiTail = e;
                    ++hc;
                }
            }

            if (loHead != null) {
    
    
                if (lc <= UNTREEIFY_THRESHOLD)
                    tab[index] = loHead.untreeify(map);
                else {
    
    
                    tab[index] = loHead;
                    if (hiHead != null) // (else is already treeified)
                        loHead.treeify(tab);
                }
            }
            if (hiHead != null) {
    
    
                if (hc <= UNTREEIFY_THRESHOLD)
                    tab[index + bit] = hiHead.untreeify(map);
                else {
    
    
                    tab[index + bit] = hiHead;
                    if (loHead != null)
                        hiHead.treeify(tab);
                }
            }
        }

猜你喜欢

转载自blog.csdn.net/liha12138/article/details/106609118