zoukankan      html  css  js  c++  java
  • 红黑树

    红黑树

    红黑树是特殊的二叉搜索树,它解决了二叉树的非平衡问题。


    红黑树的平衡性

    第一个图根节点的右子树的高度为2,左子树的高度为4;
    第二个图根节点的右子树的高度为3,左子树的高度为6;
    上面两个图是一个正确的红黑树——红黑树保证子树的高度差不超过两倍。

    红黑树的层数最多是2*log2(N+1)


    红黑规则

    红黑树是在插入删除元素的过程中通过维持其自身的特征来保持平衡的。

    红黑树的特征,也称红黑规则:
    1、根总是黑色的
    2、如果节点是红色,其子节点必黑
    3、从根到叶节点或空子节点的每条路径黑色高度(黑色节点的数目)必须相同

    空子节点,即非叶节点为空的子节点。如下图所示,如果一个非叶节点只有左子节点,那么空缺的右子节点就是一个空子节点,反之亦然


    维持红黑规则的方法

    1、改变节点颜色
    2、旋转

    在插入或删除的过程中使用颜色变换消除了树的上方出现任何违规情况,这样就不需要像AVL树那样在插入元素后从下向上做反向检查
    红黑规则和颜色变换只是有助于决定何时执行旋转,旋转才是起关键作用的操作


    实现(插入)

    插入的新节点一定是红色的,因为如果插入的节点是黑色的,一定会改变这条路径上的黑色高度。

    插入过程描述:

    下面的X表示插入的新节点或父子红红冲突时的子节点、P表示X的父节点、G表示X的祖父节点

    1、在顺着根节点向下查找插入点时,只要发现一个黑色节点有两个红色的子节点,就执行一次颜色变换,把子节点的颜色变为黑,把父节点(根节点除外)的颜色变为红。

    2、有时颜色变换会造成红红冲突,需要改变颜色,并旋转一次或两次来解决冲突。旋转次数由X是G的外侧子孙节点还是内侧子孙节点决定。
    X是左外侧节点——改变X的祖父节点的颜色,改变X的父节点的颜色;以G为顶点右旋;插入结束——如下图所示(举了三个例子都是X为左外侧节点的情况,并且采取同样的方法处理,以说明采取的方法具有一般性)。
    X是右外侧节点——改变X的祖父节点的颜色,改变X的父节点的颜色;以G为顶点左旋;插入结束。

    a图是平衡的,现在要插入0或者2或5;在下行途中发现3是黑的并且它的两个子节点是红的,于是改变颜色,产生b图;
    b图红红冲突,我们称红红冲突的子节点是X,改变X的祖父节点、父节点的颜色,于是产生了c图;
    c图现在不平衡,以G为顶端节点右旋,使其平衡,于是产生了d图;
    d图现在是平衡的;想要插入0或者2或5都可以了


    a图是平衡的,现在要插入5或者7或者17或者19;在下行途中发现12是黑的并且它的两个子节点是红的,于是改变颜色,产生b图;
    b图红红冲突,我们称红红冲突的子节点是X,改变X的祖父节点(忽略根元素不能为红)、父节点的颜色,于是产生了c图;
    c图现在不平衡且根节点为红,以G为顶端节点右旋,使其平衡,于是产生了d图;
    d图现在是平衡的;想要插入5或者7或者17或者19都可以了

    a图是平衡的,现在要插入39或者41或者54或者56;在下行途中发现50是黑的并且它的两个子节点是红的,于是改变颜色,产生b图;
    b图红红冲突,我们称红红冲突的子节点是X,改变X的祖父节点、父节点的颜色并以G为顶端节点右旋,于是产生了c图;
    c图现在是平衡的;想要插入39或者41或者54或者56都可以了

    X是左内侧节点——先右旋一次;再改变X的祖父节点的颜色,改变X的父节点的颜色;以G为顶点左旋;插入结束——如下图所示。
    X是右内侧节点——先左旋一次;再改变X的祖父节点的颜色,改变X的父节点的颜色;以G为顶点右旋;插入结束。

    a图是平衡的,现在要插入54或56或64或66;在下行途中发现60是黑的并且它的两个子节点是红的,于是改变颜色,产生b图;
    b图红红冲突,我们称红红冲突的子节点是X,但我们发现X是其祖父节点G的内侧子孙节点,所以先做一次旋转,以P为顶端节点右旋,产生了c图;
    c图还是红红冲突,不过这时的X、P已经不是原来的X和P了,正好对调了一下;同时我们还发现,问题已经转化了,转化为X是G的外侧节点;这时改变X的祖父节点、父节点的颜色;
    d以G为顶端节点左旋。
    上面的做法还有另外一种,如下图:

    不同之处在于,在b图中,改变X和G的颜色,然后右旋,左旋。

    3、继续向下查找插入点,并插入新节点X,如果P是黑色的,插入结束。
    4、新节点X插入后如果红红冲突,需要改变颜色,并旋转一次或两次来解决冲突。旋转次数由X是G的外侧子孙节点还是内侧子孙节点决定。
    X是左外侧节点——改变X的祖父节点的颜色,改变X的父节点的颜色;以G为顶点右旋;插入结束——如下图所示。
    X是右外侧节点——改变X的祖父节点的颜色,改变X的父节点的颜色;以G为顶点左旋;插入结束。

    X是左内侧节点——改变X的祖父节点的颜色,改变X的的颜色;以P为顶点左旋;以G为顶点右旋;插入结束——如下图所示。
    X是右内侧节点——改变X的祖父节点的颜色,改变X的的颜色;以P为顶点右旋;以G为顶点左旋;插入结束。


    红黑树的效率 

    红黑树的层数最多是2*log2(N+1),查找时间最差需要2*log2N次比较;平均需要log2N次比较;

    插入和删除的时间要增加一个常数因子——颜色变换和旋转。平均起来,一次插入大约需要一次旋转。因此,插入的时间复杂度还是O(log(N))。

    在下行路途中的颜色变换使红黑树的插入效率比其他平衡树比如AVL树的插入效率更高。颜色变换保证了在下行的路途中仅在树上行走一遍,而AVL树在插入后要做反向检查直到根元素。 

  • 相关阅读:
    又到一年高考时
    嵌套母版页中的控件访问
    用临时表改善嵌套SQL语句的执行速度
    利用图片进行定位
    CSS样式嵌套
    触摸MVP
    抱SQL SERVER大腿之从巨大表中提炼非重复数据
    用参数来控制用户控件的缓存
    Understand static/global data completely in C++
    VS资源(基础)
  • 原文地址:https://www.cnblogs.com/Mike_Chang/p/10210652.html
Copyright © 2011-2022 走看看