红黑树

来源:互联网 发布:curl 发送json数据 编辑:程序博客网 时间:2024/04/30 20:39

红黑树是什么

红黑树是一种树形数据结构,它的节点值的大小是按照左节点<父节点<右节点 这种顺序排列的。所有在搜索红黑树的值时,其复杂度是Olg(n)。如果有一组数据1,2,3,4,5,6,7按照这种顺序插入到树中,会导致所有的数据都在右节点上,这时候去这个树中搜索数据时,其复杂度依然是n,并没有任何优化,这是因为这种树结构左右失衡造成的。因此就有了平衡树这种数据结构,当发现左右节点深度不平衡时,通过一些方式使其达到平衡。但是深度高度一致的平衡树在插入数据时,会频繁的引起树的修复工作,虽然优化了查询速度,但在树的生成中会引入更多的操作,造成其复杂度的上升。红黑树对于树的高度不要求强一致,这样使其查询和插入的速度都可以。

这里写图片描述

红黑树的性质

性质1. 节点是红色或黑色。

性质2. 根节点是黑色。

性质3. 每个叶节点(NIL节点,空节点)是黑色的。

性质4. 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)

性质5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

红黑树的构建

插入

对于插入我们可以分情况讨论,但对于红黑树插入其实分为两步,一步插入,一步插入修复,插入修复就是使其插入新的节点要维持5条性质

删除

删除主要分两个环节,找到要删除的节点并且删除。删除后恢复红黑树的性质。

修复

修复树的结构主要包括旋转和重新染色两种方式。

这里着重对旋转进行描述,一共分为左旋和右旋两种。

左旋
 对红黑树的节点(x)进行左旋转     *     * 左旋示意图(对节点x进行左旋):     *      px                              px     *     /                               /     *    x                               y                     *   /  \      --(左旋)-.           / \                #     *  lx   y                          x  ry          *     /   \                       /  \     *    ly   ry                     lx  ly  

上面对x节点进行了左旋,就是将x往左下拉一下。

大致分为4步

1.获取x(被旋转的节点)的右孩子

2.将y的左孩子设置为x的右孩子(设置x的left和ly的parent)

3.修改y的父亲节点(设置y.parent和px.left或者px.right)

4.将x的parent设置为y(y的左儿子设置为x)

private void leftRotate(RBTNode<T> x) {        RBTNode<T> y = x.right;        //将 “y的左孩子” 设为 “x的右孩子”;        // 如果y的左孩子非空,将 “x” 设为 “y的左孩子的父亲”        x.right = y.left;        if (y.left != null)            y.left.parent = x;        // 将 “x的父亲” 设为 “y的父亲”        y.parent = x.parent;        if (x.parent == null) {            this.mRoot = y;            // 如果 “x的父亲” 是空节点,则将y设为根节点        } else {            if (x.parent.left == x)                x.parent.left = y;    // 如果 x是它父节点的左孩子,则将y设为“x的父节点的左孩子”            else                x.parent.right = y;    // 如果 x是它父节点的左孩子,则将y设为“x的父节点的左孩子”        }        // 将 “x” 设为 “y的左孩子”        y.left = x;        // 将 “x的父节点” 设为 “y”        x.parent = y;    }

右旋

     * 对红黑树的节点(y)进行右旋转     *     * 右旋示意图(对节点y进行左旋):     *            py                               py     *           /                                /     *          y                                x                       *         /  \      --(右旋)-.            /  \                     #     *        x   ry                           lx   y       *       / \                                   / \                   #     *      lx  rx                                rx  ry
 private void rightRotate(RBTNode<T> y) {        RBTNode<T> x = y.left;        // 将 “x的右孩子” 设为 “y的左孩子”;        // 如果"x的右孩子"不为空的话,将 “y” 设为 “x的右孩子的父亲”        y.left = x.right;        if (x.right != null)            x.right.parent = y;        // 将 “y的父亲” 设为 “x的父亲”        x.parent = y.parent;        if (y.parent == null) {            this.mRoot = x;            // 如果 “y的父亲” 是空节点,则将x设为根节点        } else {            if (y == y.parent.right)                y.parent.right = x;    // 如果 y是它父节点的右孩子,则将x设为“y的父节点的右孩子”            else                y.parent.left = x;    // (y是它父节点的左孩子) 将x设为“x的父节点的左孩子”        }        // 将 “y” 设为 “x的右孩子”        x.right = y;        // 将 “y的父节点” 设为 “x”        y.parent = x;    }

该文章只是简单的分析红黑树到底是什么,树的构建的详情可以在代码中可以看到。想真正的理解红黑树插入和删除的修复环节的理由,推荐去看算法导论,好好推理。

这里是红黑树java版代码
https://github.com/yangzhenkun/learn/tree/master/src/main/java/com/yasin/datastruct/rbtree

阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 开尔青年队 开尔小棚 开尔爱心公棚 300234开尔新材 开尔新材 300234 开山网 开山岛 朱开山 神棍开山祖 开山 开山空压机 开山股份 朱开山原型 五丁开山 殷开山 开山采珠 开山膨胀剂 开山破碎锤 开山钻机 开山 空压机 开山集团 开山路 浙江开山 开山压缩机 九叔开山大弟子 洪荒之神棍开山祖师 开山岛为什么不住驻兵 洪荒神棍开山之祖 开山岛王继才年薪多少 台州的开山网 洪荒之神棍开山祖txt下载 开山空压机售后服务 开山空压机多少钱 开山螺杆空压机配件 开山牌螺杆式空压机 开山股份股票 开山潜孔钻机价格 开山牌空压机 300257开山股份 开山股份有限公司