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

平衡二叉树(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.right
		RB-Transplant(T,z,z.right)
	else if(z.right==T.nil)
		x=z.left
		RB-Transplant(T,z,z.left)
	else y=Tree-min(z.right)
		y-original-color=y.color
		x=y.right
		if(y.parent==z)
			x.parent=y 
		else RB-Transplant(T,y,y.right)
			y.right=z.right
			y.right.parent=y 
		RB-Transplant(T,z,y)
		y.left=z.left
		y.left.parent=y 
		y.color=z.color
	if(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:红黑树这块真是要把我弄晕了《平衡二叉树各种算法详解一:红黑树》

    原文作者:平衡二叉树
    原文地址: https://blog.csdn.net/qq_29407877/article/details/49556143
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞