Java 8 HashMap(九)——TreeNode的removeTreeNode和balanceDeletion

说明看注释

一、removeTreeNode

        /**
         * @param movable 处理时,是否移动其他节点
         */
        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;
            //找到这个位置上的第一个树节点first,并标记为root节点
            TreeNode<K, V> first = (TreeNode<K, V>) tab[index], root = first, rl;
            //succ 表示当前要删除的节点的后节点, pred 表示其前节点
            TreeNode<K, V> succ = (TreeNode<K, V>) this.next, pred = this.prev;
            if (pred == null) {
                //如果pred节点不存在,则表示当前节点为根节点
                //删除后succ节点成为根节点,用fist节点标记,并放在数组上
                tab[index] = first = succ;
            } else {
                //如果pred节点存在
                //则将pred节点的后节点指向succ节点
                pred.next = succ;
            }
            if (succ != null) {
                //如果succ节点存在,则将succ节点的前节点指向pred节点
                succ.prev = pred;
            }
            if (first == null) {
                //如果当前节点不存在,直接返回
                return;
            }
            //如果root节点的父节点存在,说明当前root节点不是根节点
            if (root.parent != null) {
                //获取真实根节点
                root = root.root();
            }
            //以上做法是先整理当前节点上的链表关系,接下来整理红黑树关系
            //根据当root节点和它的左右节点的一些情况,判断红黑树节点的数量
            if (root == null || root.right == null || (rl = root.left) == null || rl.left == null) {
                //太小了,转换为链表
                tab[index] = first.untreeify(map);
                return;
            }
            //p 当前节点,pl p节点的左节点,pr p节点的右节点
            //replacement p节点删除后代替他的节点
            TreeNode<K, V> p = this, pl = p.left, pr = p.right, replacement;
            if (pl != null && pr != null) {
                //当删除p节点,但是他的左右节点不为空时,遍历他的右节点上的左子树(以下操作先让p节点和s节点交换位置,然后找到replacement节点替换他)
                TreeNode<K, V> s = pr, sl;
                while ((sl = s.left) != null) {
                    s = sl;
                }
                //通过上述操作,s节点是大于p节点的最小节点(替换他的节点)
                //将s节点和p节点的颜色交换
                boolean c = s.red;
                s.red = p.red;
                p.red = c;
                //sr s节点的右节点
                TreeNode<K, V> sr = s.right;
                //pp p节点的父节点
                TreeNode<K, V> pp = p.parent;
                //如果pr节点就是s节点
                if (s == pr) {
                    //交换他们的关系
                    p.parent = s;
                    s.right = p;
                } else {
                    //获得s节点的父节点sp
                    TreeNode<K, V> sp = s.parent;
                    //将p节点的父节点指向sp,且sp节点存在
                    if ((p.parent = sp) != null) {
                        //判断s节点在sp节点的哪一侧,将p节点放在s节点的那一侧
                        if (s == sp.left) {
                            sp.left = p;
                        } else {
                            sp.right = p;
                        }
                    }
                    //将pr节点变成s节点的右节点,且pr节点存在
                    if ((s.right = pr) != null) {
                        //将s节点变成pr节点的父节点
                        pr.parent = s;
                    }
                }
                //因为s节点的性质,s节点没有左节点
                //当下p节点和s节点交换了位置,所以将p节点的左节点指空
                p.left = null;
                //将sr节点的变成p节点的右节点,且sr节点存在
                if ((p.right = sr) != null) {
                    //将p节点变成sr节点的父节点
                    sr.parent = p;
                }
                //将pl节点变成s节点的左节点,且pl节点存在
                if ((s.left = pl) != null) {
                    //将s节点变成pl节点的父节点
                    pl.parent = s;
                }
                //如果pp节点不存在,那当前s节点就是根节点
                if ((s.parent = pp) == null) {
                    //将root节点指向s节点
                    root = s;
                } else if (p == pp.left) {
                    //如果pp节点存在,且p节点是pp节点的左节点
                    //将s节点变成pp节点的左节点
                    pp.left = s;
                } else {
                    //将s节点变成pp节点的右节点
                    pp.right = s;
                }
                //如果sr节点存在
                if (sr != null) {
                    //将replacement节点变成sr节点
                    replacement = sr;
                } else {
                    //sr节点不存在,将replacement变成p节点
                    replacement = p;
                }
            } else if (pl != null) {
                //如果pl节点存在,pr节点不存在,不用交换位置,pl节点成为replacement节点
                replacement = pl;
            } else if (pr != null) {
                //如果pr节点存在,pl节点不存在,不用交换位置,pr节点成为replacement节点
                replacement = pr;
            } else {
                //如果都不存在,p节点成为replacement节点
                replacement = p;
            }
            //将以下判断跟上述判断分开看,仅以p节点的当前位置性质,对replacement节点进行操作
            if (replacement != p) {
                //如果replacement不是p节点
                //将p节点的父节点pp变成replacement节点的父节点
                TreeNode<K, V> pp = replacement.parent = p.parent;
                //如果pp节点不存在
                if (pp == null) {
                    //replacement节点成为根节点
                    root = replacement;
                } else if (p == pp.left) {
                    //如果pp节点存在,根据p节点在pp节点的位置,设置replacement节点的位置
                    pp.left = replacement;
                } else {
                    pp.right = replacement;
                }
                //将p节点的所有树关系关系指空
                p.left = p.right = p.parent = null;
            }
            //如果p节点是红色,删除后不影响root节点,如果是黑色,找到平衡后的根节点,并用节点r表示
            TreeNode<K, V> r = p.red ? root : balanceDeletion(root, replacement);
            //如果p节点是replacement节点
            if (replacement == p) {
                //得到p节点父节点pp
                TreeNode<K, V> pp = p.parent;
                //将p节点的父节点指空
                p.parent = null;
                if (pp != null) {
                    //如果pp节点存在
                    //根据p节点的位置,将pp节点的对应位置指空
                    if (p == pp.left) {
                        pp.left = null;
                    } else if (p == pp.right) {
                        pp.right = null;
                    }
                }
            }
            //移动新的跟节点到数组上
            if (movable) {
                moveRootToFront(tab, r);
            }
        }

二、balanceDeletion

        static <K, V> TreeNode<K, V> balanceDeletion(TreeNode<K, V> root, TreeNode<K, V> x) {
            //x 当前要删除的节点
            //xp x节点的父节点
            //xpl xp节点的左节点
            //xpr xp节点的右节点
            TreeNode<K, V> xp, xpl, xpr;
            for (; ; ) {
                if (x == null || x == root) {
                    //如果x节点为空,或x节点是根节点
                    return root;
                } else if ((xp = x.parent) == null) {
                    //当xp节点为空时,说明x为根节点,将x节点设置为黑色,并返回x节点
                    x.red = false;
                    return x;
                } else if (x.red) {
                    //x节点是红色,无需调整
                    x.red = false;
                    return root;
                } else if ((xpl = xp.left) == x) {
                    //如果x节点为xpl节点
                    if ((xpr = xp.right) != null && xpr.red) {
                        //如果xpr节点不为空,且xpr节点是红色的
                        //将xpr设置为黑色,xp设置为红色
                        xpr.red = false;
                        xp.red = true;
                        //左旋
                        root = rotateLeft(root, xp);
                        //重新将xp节点指向x节点的父节点,并将xpr节点指向xp的右节点
                        xpr = (xp = x.parent) == null ? null : xp.right;
                    }
                    if (xpr == null) {
                        //若xpr节点不存在
                        //则将x节点指向xp节点向上调整
                        x = xp;
                    } else {
                        //sl xpr节点的左节点
                        //sr xpr节点的右节点
                        TreeNode<K, V> sl = xpr.left, sr = xpr.right;
                        if ((sr == null || !sr.red) &&
                                (sl == null || !sl.red)) {
                            //若sr节点为空或者sr节点是黑色的,且sl节点为空或者sl节点是黑色的
                            //将xpr节点变成红色
                            xpr.red = true;
                            //则将x节点指向xp节点向上调整
                            x = xp;
                        } else {
                            //sr和sl中存在一个红节点
                            if (sr == null || !sr.red) {
                                //此处说明sl是红节点,将sl节点设置为黑色
                                sl.red = false;
                                //将xpr节点设置为红色
                                xpr.red = true;
                                //右旋
                                root = rotateRight(root, xpr);
                                //将xpr节点重新指向xp节点的右节点
                                xpr = (xp = x.parent) == null ? null : xp.right;
                            }
                            if (xpr != null) {
                                //如果xpr节点不为空,让xpr节点与xp节点同色
                                xpr.red = (xp == null) ? false : xp.red;
                                //当sr节点不为空,变成黑色
                                if ((sr = xpr.right) != null) {
                                    sr.red = false;
                                }
                            }
                            //存在xp节点
                            if (xp != null) {
                                //将xp节点设置为黑色
                                xp.red = false;
                                //进行左旋
                                root = rotateLeft(root, xp);
                            }
                            //将x节点指向root进行下一次循环时跳出
                            x = root;
                        }
                    }
                } else {
                    //当x节点是右节点
                    if (xpl != null && xpl.red) {
                        //当xpl节点存在且为红色
                        //将xpl变为黑色,xp变为红色
                        xpl.red = false;
                        xp.red = true;
                        //右旋
                        root = rotateRight(root, xpl);
                        //将xpl节点重新指向xp节点的左节点
                        xpl = (xp = x.parent) == null ? null : xp.left;
                    }
                    if (xpl == null) {
                        //如果xpl节点不存在,则xp节点没有子节点了
                        //将x节点指向xp节点向上调整
                        x = xp;
                    } else {
                        //sl xpl节点的左节点
                        //sr xpl节点的右节点
                        TreeNode<K, V> sl = xpl.left, sr = xpl.right;
                        if ((sl == null || !sl.red) && (sr == null || !sr.red)) {
                            //若sr节点为空或者sr节点是黑色的,且sl节点为空或者sl节点是黑色的
                            //将xpl节点变成红色
                            xpl.red = true;
                            //则将x节点指向xp节点向上调整
                            x = xp;
                        } else {
                            //sr和sl中存在一个红节点
                            if (sl == null || !sl.red) {
                                //此处说明sr是红节点,将sr节点设置为黑色
                                sr.red = false;
                                //将xpr节点设置为红色
                                xpl.red = true;
                                //左旋
                                root = rotateLeft(root, xpl);
                                //将xpl节点重新指向xp节点的左节点
                                xpl = (xp = x.parent) == null ? null : xp.left;
                            }
                            //如果xpl节点存在
                            if (xpl != null) {
                                //使xpl节点与xp节点同色
                                xpl.red = (xp == null) ? false : xp.red;
                                //如果sl节点存在
                                if ((sl = xpl.left) != null) {
                                    //将sl节点变为黑色
                                    sl.red = false;
                                }
                            }
                            //如果xp节点存在
                            if (xp != null) {
                                //将xp节点设置为黑色
                                xp.red = false;
                                //右旋
                                root = rotateRight(root, xp);
                            }
                            //将x节点指向root进行下一次循环时跳出
                            x = root;
                        }
                    }
                }
            }
        }

上一篇:XP系统不识别GPT大容量硬盘试验没有成功


下一篇:xp系统假死,鼠标能动,但桌面卡住,任务管理器调不出来 2021.03.29