3、JDK1.8HashMap源码分析系列文章(moveRootToFront、checkInvariants)

1、TreeNode静态方法:验证红黑树的准确性,checkInvariants(该方法需要在启动参数中加 -ae 才能生效)

        /**
         * 验证红黑树的准确性
         *
         * @param t 数据验证的起始根节点
         * @return boolean
         * @Author muyi
         * @Date 17:53 2020/7/30
         */
        static <K, V> boolean checkInvariants(HashMap.TreeNode<K, V> t) {
            // tp-父节点,tl-左子节点,tr-右子节点,tp-前驱节点,tn-后继节点
            HashMap.TreeNode<K, V> tp = t.parent, tl = t.left, tr = t.right,
                    tb = t.prev, tn = (HashMap.TreeNode<K, V>) t.next;
            // 当出现以下任一情况时,红黑树或者双向链表不正确
            // 1、如果前驱节点存在,但是前驱节点的后继节点不是当前节点
            if (tb != null && tb.next != t)
                return false;
            // 2、如果后继节点存在,但是后继节点的前驱节点不是当前节点
            if (tn != null && tn.prev != t)
                return false;
            // 3、父节点存在,但是父节点的左子节点、右子节点均不是当前节点
            if (tp != null && t != tp.left && t != tp.right)
                return false;
            // 4、左子节点存在。但是左子节点的父节点不是当前节点或者左子节点的hash值大于当前节点的hash值
            if (tl != null && (tl.parent != t || tl.hash > t.hash))
                return false;
            // 5、右子节点存在。但是右子节点的父节点不是当前节点或者右子节点的hash值小于当前节点的hash值
            if (tr != null && (tr.parent != t || tr.hash < t.hash))
                return false;
            // 6、当前节点是红色,孩子节点也是红色
            if (t.red && tl != null && tl.red && tr != null && tr.red)
                return false;
            // 递归验证左子树
            if (tl != null && !checkInvariants(tl))
                return false;
            // 递归验证右子树
            if (tr != null && !checkInvariants(tr))
                return false;
            // 都正确返回true
            return true;
        }

2、TreeNode静态方法:将红黑树的root节点移动到tab相对应的索引位置,moveRootToFront

        /**
         * 将红黑树的root节点移动到tab相对应的索引位置
         * 在树化的过程中,所有的节点的prev、next值均未改变,这里可以简单的理解为对双向链表进行维护
         *
         * @param tab  数组表
         * @param root 红黑树的根节点
         * @return void
         * @Author muyi
         * @Date 17:25 2020/7/30
         */
        static <K, V> void moveRootToFront(HashMap.Node<K, V>[] tab, HashMap.TreeNode<K, V> root) {
            int n;
            if (root != null && tab != null && (n = tab.length) > 0) {
                // 计算索引
                int index = (n - 1) & root.hash;
                // 原链表的头节点
                HashMap.TreeNode<K, V> first = (HashMap.TreeNode<K, V>) tab[index];
                // 如果头节点和红黑树的root节点不相等,就需要找到root节点在链表中位置,并在链表中进行数据交换
                if (root != first) {
                    // 后继节点
                    HashMap.Node<K, V> rn;
                    tab[index] = root;
                    // root的前驱节点
                    HashMap.TreeNode<K, V> rp = root.prev;
                    // 如果root的后继节点存在,则将它的前驱节点指向root的前驱节点
                    if ((rn = root.next) != null)
                        ((HashMap.TreeNode<K, V>) rn).prev = rp;
                    // 如果root的前驱节点存在,则将它的后继节点指向root的后继节点
                    if (rp != null)
                        rp.next = rn;
                    // 链表中的头节点存在,则将他的前驱节点指向root
                    if (first != null)
                        first.prev = root;
                    // root的后继节点指向头节点
                    root.next = first;
                    // root的前驱节点指向null
                    root.prev = null;
                }
                // 递归不变检查(验证红黑树的正确性)
                assert checkInvariants(root);
            }
        }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值