平衡二叉树各种算法详解一:红黑树

来源:互联网 发布:武汉java培训班 编辑:程序博客网 时间:2024/05/22 06:48

平衡二叉树(Balanced Binary Tree)具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。平衡二叉树的常用算法有红黑树、AVL、Treap、伸展树、SBT等。最小二叉平衡树的节点的公式如下 F(n)=F(n-1)+F(n-2)+1 这个类似于一个递归的数列,可以参考Fibonacci数列,1是根节点,F(n-1)是左子树的节点数量,F(n-2)是右子树的节点数量。平衡二叉树的时间复杂度为o(h),h为树高,保持树矮胖的形态有利于提高算法的效率。

平衡二叉树中常见操作有插入,删除,旋转等。

旋转是维持平衡二叉树必要的操作,包括左旋和右旋,二者成镜像对称。

左旋算法如下(T.ROOT表示树根,NIL表示空结点)

def Left-Rotate(x):    y=x.right    if(y.left!=NIL):        y.left.parent=x        x.right=y.left    if(x.parent==NIL):        T.ROOT=y    else if(x.parent.left==x):        x.parent.left=y    else x.parent.right=y    y.parent=x.parent    x.parent=y    y.left=x

右旋与之类似,故不再贴出代码。

插入算法如下:

def Tree-Insert(T,z):    y=NIL         //use y as the parent of x    x=T.ROOT    while(x!=NIL):        y=x        if(z.value<x.value):            x=x.left        else x=x.right    z.parent=y    if(y==NIL):    //tree is empty        T.ROOT=z    else if(z.value<y.value):        y.left=z    else y.right=z

删除算法需要考虑三种情况:

1. z没有子结点,直接删除,修改z的父结点,再用NIL替代z即可

2. z只有一个子结点,将其提升到z的位置,修改z的父结点,再用z的子结点代替z

3. z有两个子结点,这时稍麻烦一点,需要寻找z的后继,即z的右子树中最小的一个结点,还要考虑后继正好为z的右孩子的情况

首先定义一个子树的移植算法:

def Transplant(T,u,v):      //用以v为根的子树替代以U为根的子树    if(u.parent==NIL)        T.ROOT=v    else if(u==u.parent.left)        u.parent.left=v    else u.parent.right=v    if(v!=NIL)        v.parent=u.parent

再定义一个寻找后继的方法:

def Tree-min(z):    if(z.left!=NIL)        z=z.left    return z

利用现成的移植算法进行删除:

def Tree-delete(T,z)    if(z.left==NIL)        Transplant(T,z,z.right)    else if(z.right==NIL)        Transplant(T,z,z.left)    else y=Tree-min(z.right)       //y is the successor of z        if(y.parent!=z)            Transplant(T,y,y.right)            y.right=z.right            y.right.parent=y        Transplant(T,z,y)        z.left.parent=y        y.left=z.left

这就是平衡二叉树中常见的旋转,插入,删除算法。由于插入,删除有可能改变树的平衡性,所以需调用旋转方法以保持树的平衡性。

下面举例详解各种平衡二叉树。

红黑树:

红黑树(Red Black Tree) 是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。红黑树在很多地方都有应用。在C++ STL中,很多部分(包括set, multiset, map, multimap)应用了红黑树的变体(SGI STL中的红黑树有一些变化,这些修改提供了更好的性能,以及对set操作的支持)。

红黑树是每个节点都带有颜色属性的二叉查找树,颜色或红色或黑色。在二叉查找树强制一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求:
性质1. 节点是红色或黑色。
性质2. 根节点是黑色。
性质3 每个叶节点(NIL节点,空节点)是黑色的。
性质4 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
性质5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
这些约束强制了红黑树的关键性质: 从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。结果是这个树大致上是平衡的。因为操作比如插入、删除和查找某个值的最坏情况时间都要求与树的高度成比例,这个在高度上的理论上限允许红黑树在最坏情况下都是高效的,而不同于普通的二叉查找树。

红黑树的插入:

def RB-Insert(T,z):    y=T.nil         //use y as the parent of x    x=T.ROOT    while(x!=T.nil):        y=x        if(z.value<x.value):            x=x.left        else x=x.right    z.parent=y    if(y==T.nil):    //tree is empty        T.ROOT=z    else if(z.value<y.value):        y.left=z    else y.right=z    z.left=T.nil    z.right=T.nil    z.color=RED       //z is red     RB-Insert-fixup(T,z)   //make the tree follow red-black rule
插入后修复树的颜色:def RB-Insert-fixup(T,z)    while(z.parent.color==RED)        if(z.parent==z.parent.parent.left)            y=z.parent.parent.right            //y is the uncle node of z             if(y.color==RED)                   //case 1                z.p.color=BLACK                y.color=BLACK                z.parent.parent.color=RED                z=z.parent.parent            else if(z==z.parent.right)          //case 2                z=z.parent                Left-Rotate(T,z)            z.parent.color=BLACK                //case 3            z.parent.parent.color=RED            Right-Rotate(T,z.parent.parent)     <pre name="code" class="python">        else (same as "then" clause with right and left exchanged)  //if a.parent==z.parent.parent.left,case 1,2,3with right and left exchanged
 T.ROOT.color=BLACK

红黑树的删除:

同样先定义一个移植算法:

def RB-Transplant(T,u,v):      //用以v为根的子树替代以U为根的子树    if(u.parent==T.nil)        T.ROOT=v    else if(u==u.parent.left)        u.parent.left=v    else u.parent.right=v    v.parent=u.parent

删除算法:


def RB-delete(T,z)y=z y-original-color=y.color if(z.left==T.nil)x=z.rightRB-Transplant(T,z,z.right)else if(z.right==T.nil)x=z.leftRB-Transplant(T,z,z.left)else y=Tree-min(z.right)y-original-color=y.colorx=y.rightif(y.parent==z)x.parent=y else RB-Transplant(T,y,y.right)y.right=z.righty.right.parent=y RB-Transplant(T,z,y)y.left=z.lefty.left.parent=y y.color=z.colorif(y-original-color==BLACK)RB-delete-fixup(T,x)

删除后的修复颜色属性操作

RB-delete-fixup(T,x):

def RB-delete-fixup(T,x)    while(x!=T.ROOT&&x.color==BLACK)        if(x==x.parent.left)            w=x.parent.right            if(w.color==RED)                     //case 1                w.color=BlACK                x.parent.color=RED                Left-Rotate(T,x.parent)                w=x.parent.right            if(w.left.color==BLACK&&w.right.color==BLACK)       //case 2                w.color=RED                x=x.parent            else if(w.right.color==BLACK)        //case 3                w.left.color=BLACK                w.color=RED                Right-Rotate(T,w)                w=x.parent.right            w.color=x.parent.color               //case 4            x.parent.color=BLACK            w.right.color=BLACK            Left-Rotate(T,x.parent)            x=T.ROOT        else (same as "then" clause with right and left exchanged)    x.color=BLACK

相关资料可见维基百科上关于红黑树的讲解

(ps:红黑树这块真是要把我弄晕了再见



0 0