平衡二叉树(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:红黑树这块真是要把我弄晕了)