红黑树
来源:互联网 发布: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