红黑树详解

1972年由Rudolf Bayer发明的,当时被称为平衡二叉B树(symmetric binary B-trees)。后来,在1978年被 Leo J. Guibas 和 Robert Sedgewick 修改为如今的“红黑树”。

红黑树和AVL树类似,都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能。

它虽然是复杂的,但它的最坏情况运行时间也是非常良好的,并且在实践中是高效的: 它可以在O(log n)时间内做查找,插入和删除,这里的n 是树中元素的数目。

红黑树的五个性质:

1)每个结点要么是红的,要么是黑的。
2)根结点是黑的。
3)每个叶结点,即空结点(NIL)是黑的。
4)如果一个结点是红的,那么它的俩个儿子都是黑的。

5)对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点



树的插入删除,会影响树的特性

红黑树操作:
插入节点为红色N,被插入的节点为P,P的父节点为G,P的叔叔节点为U


树的插入删除,会影响树的特性
插入:
1.插入节点的父亲节点为黑色,不会影响树的性能。所以不用改变。
2.插入节点的父亲节点为红色,会分成3中情况:
    a)叔叔节点为红色。

       无论N在P左右,P在G的左右。把G换成红色,把P、U换成黑色。然后把G当成插入点向上验证树的特性。


    b)叔叔节点为黑色或者没有。

所有情况如下图



发生下面情况发生变色右旋(G变红,P变成红色)




发生下面情况发生变色左旋(G变红,P变成红色)



发生下面情况发生右旋和变色左旋情况


发生下面情况发生左旋和变色右旋情况.第二个图形中PN位置反了



删除: 

1.删除节点没有子节点,直接删除。

2.删除节点有子节点。

a)删除节点的孩子节点是单支节点(没有孩子节点),或者前继(节点左边最大的节点)后继(节点右边最小的节点)为单节点。直接替换与换颜色,移除删除的。如下:R为要删除的节点,M是R右边最小值。


b)R为要删除的节点,M是R右边最小值。N是M的右节点。R与M位置与颜色互换。N替换R。




如果发生b)种情况。N的位置变化会影响红黑树的特性。







U节点为红色:



U、UL、UR都为黑色:




U、UR为黑,UL为红:



U为黑色、UR为红色:




jdk1.8  HashMap.TreeNode的部分代码详解

//排序新插入的数据 并返回root节点
static <K,V> TreeNode<K,V> balanceInsertion(TreeNode<K,V> root,
                                                    TreeNode<K,V> x) {//x为新插入的treenode
            x.red = true;//默认设置成[红]
            for (TreeNode<K,V> xp, xpp, xppl, xppr;;) {
                if ((xp = x.parent) == null) {//x的父节点为xp,如果xp为空,那么xp就是root,因为红黑树中只有root节点的父节点为null
                    x.red = false;
                    return x;
                }
                else if (!xp.red || (xpp = xp.parent) == null)//xp为黑,不影响树的特征,直接插入。
                                                                //x的祖父节点为null,xp为root,树高为1不影响性能。
                    return root;
                if (xp == (xppl = xpp.left)) {//在祖父节点左边的树。
                    if ((xppr = xpp.right) != null && xppr.red) {//父亲节点右边节点为红色。
                        xppr.red = false;
                        xp.red = false;
                        xpp.red = true;
                        x = xpp;//检查祖父接单是否符合树的特性。进行下一次循环。
                    }
                    else {//祖父节点右边节点为黑色或没有
                        if (x == xp.right) {//插入节点在父节点的右边
                            root = rotateLeft(root, x = xp);//左旋转,
                            xpp = (xp = x.parent) == null ? null : xp.parent;//x为旋转后的子节点(原父亲节点),xp
                                                                                //x为旋转后的父节点(原子亲节点)
                        }
                        if (xp != null) {
                            xp.red = false;//xp(原插入节点)设成黑
                            if (xpp != null) {
                                xpp.red = true;
                                root = rotateRight(root, xpp);//右旋
                            }
                        }
                    }
                }
                else {//在祖父节点右边的树。
                    if (xppl != null && xppl.red) {//父亲节点右边节点为红色。
                        xppl.red = false;
                        xp.red = false;
                        xpp.red = true;
                        x = xpp;//检查祖父接单是否符合树的特性。进行下一次循环。
                    }
                    else {
                        if (x == xp.left) {
                            root = rotateRight(root, x = xp);
                            xpp = (xp = x.parent) == null ? null : xp.parent;
                        }
                        if (xp != null) {
                            xp.red = false;
                            if (xpp != null) {
                                xpp.red = true;
                                root = rotateLeft(root, xpp);
                            }
                        }
                    }
                }
            }
        }

//删除treeNode后 ,发生位置变化的节点,触发的tree 的排序
static <K,V> TreeNode<K,V> balanceDeletion(TreeNode<K,V> root,
                                                   TreeNode<K,V> x) {
            for (TreeNode<K,V> xp, xpl, xpr;;)  {
                if (x == null || x == root)
                    return root;
                else if ((xp = x.parent) == null) {
                    x.red = false;
                    return x;
                }
                else if (x.red) {
                    x.red = false;
                    return root;
                }
                else if ((xpl = xp.left) == x) {//x是P的左节点
                    if ((xpr = xp.right) != null && xpr.red) {//兄弟节点为 红
                        xpr.red = false;
                        xp.red = true;
                        root = rotateLeft(root, xp);
                        xpr = (xp = x.parent) == null ? null : xp.right;
                    }
                    if (xpr == null)
                        x = xp;
                    else {
                        TreeNode<K,V> sl = xpr.left, sr = xpr.right;
                        if ((sr == null || !sr.red) &&
                            (sl == null || !sl.red)) { //xpr的孩子节点非红
                            xpr.red = true;
                            x = xp;
                        }
                        else {//xpr的孩子节点至少有一个为红
                            if (sr == null || !sr.red) {//xpr的右孩子节点非红,那么左孩子节点一定是红
                                if (sl != null)
                                    sl.red = false;
                                xpr.red = true;
                                root = rotateRight(root, xpr);
                                xpr = (xp = x.parent) == null ?
                                    null : xp.right;
                            }
                            if (xpr != null) {
                                xpr.red = (xp == null) ? false : xp.red;
                                if ((sr = xpr.right) != null)
                                    sr.red = false;
                            }
                            if (xp != null) {
                                xp.red = false;
                                root = rotateLeft(root, xp);
                            }
                            x = root;
                        }
                    }
                }
                else { // x是P的右节点。操作顺序相反
                    if (xpl != null && xpl.red) {
                        xpl.red = false;
                        xp.red = true;
                        root = rotateRight(root, xp);
                        xpl = (xp = x.parent) == null ? null : xp.left;
                    }
                    if (xpl == null)
                        x = xp;
                    else {
                        TreeNode<K,V> sl = xpl.left, sr = xpl.right;
                        if ((sl == null || !sl.red) &&
                            (sr == null || !sr.red)) {
                            xpl.red = true;
                            x = xp;
                        }
                        else {
                            if (sl == null || !sl.red) {
                                if (sr != null)
                                    sr.red = false;
                                xpl.red = true;
                                root = rotateLeft(root, xpl);
                                xpl = (xp = x.parent) == null ?
                                    null : xp.left;
                            }
                            if (xpl != null) {
                                xpl.red = (xp == null) ? false : xp.red;
                                if ((sl = xpl.left) != null)
                                    sl.red = false;
                            }
                            if (xp != null) {
                                xp.red = false;
                                root = rotateRight(root, xp);
                            }
                            x = root;
                        }
                    }
                }
            }
        }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值