红黑树详解

来源:互联网 发布:程序员的成长之路 编辑:程序博客网 时间:2024/06/05 06:42

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;                        }                    }                }            }        }


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 天猫退货上门取件退两件怎么办 买二手苹果手机没有账号怎么办 手机淘宝足迹不更新怎么办 淘宝申请退款不想退了怎么办 荣耀3c主板坏了怎么办 荣耀10天气删了怎么办 荣耀7i手机卡顿怎么办 荣耀v9总是自己拨号怎么办 华为荣耀5x很卡怎么办 华为荣耀6plus卡怎么办 华为手机触屏不灵敏怎么办 华为荣耀6x太卡怎么办 华为荣耀7太卡怎么办 荣耀手机开不开机怎么办 华为g750手机开不了机怎么办 华为手机开不了机怎么办 小米手机刷机后激活不了帐号怎么办 魅蓝note5卡顿怎么办 魅蓝note5卡了怎么办 魅蓝note5很卡怎么办 魅蓝note5锁了怎么办 荣耀9开不开机怎么办 4s更新后用不了怎么办 魅蓝3开不了机怎么办 手机不支持联通4g网络怎么办 华为手机出现emui界面怎么办 华为畅玩4x内存不足怎么办 手机电源键掉了怎么办 手机电源键坏了怎么办 小米5s听筒声音小怎么办 荣耀8电源键失灵怎么办 华为荣耀3c卡怎么办 大王卡是2g网络怎么办 联通停用2g副卡怎么办 华为荣耀8忘记解锁密码怎么办 华为手机内存满了怎么办 华为手机无限重启怎么办 华为3c重启怎么办 荣耀6 无限重启怎么办 手机进水无法开机了怎么办 华为手机不停重启怎么办