STL源码—红黑树(TT)

来源:互联网 发布:手机淘宝客服图片 编辑:程序博客网 时间:2024/05/21 17:40

红黑树的性质:

首先红黑树也是一种平衡的搜索二叉树,下面几条性质也是保证了他平衡的:

  1. 每个节点或是红色的,或是黑色的。
  2. 根节点是黑色的。
  3. 每个叶节点(NULL)是黑色的。
  4. 如果一个节点是红色的,则它的两个孩子节点都是黑色的。
  5. 对每个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点。



当对红黑树进行插入和删除操作时,会违背红黑树的性质,为了维护这些性质,必须要改变树中某些节点的颜色以及指针结构。指针结构的修改时通过旋转来完成的,这是一种能保持二叉查找树性质的查找树局部操作。

左旋转:

    当在某个节点x上做左旋转操作时,假设它的右孩子为y而不是NULL,左旋转以x到y的链为“支轴”进行。它使y成为该子树的新的根节点,x成为y的左孩子,y的左孩子成为x的右孩子。

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. LEFT_ROTATE(T,x)  
  2.    y = right[x]   //获取右孩子  
  3.    rihgt[x] = left[y]  //设置x的右孩子为y的左孩子  
  4.    if left[y] != NULL  
  5.        then parent[left[y]] = x  
  6.     parent[y] = parent[x]  //设置y的父节点为x的父节点  
  7.     if parent[x] == NULL  
  8.        then root[T] = y  
  9.        else if x==left[parent[x]  
  10.               then left[parent[x]] = y  
  11.               else  right[[parent[x]] = y  
  12.     left[y] = x  //设置y的左孩子为x  
  13.     parent[x] =y  


右旋转:

右旋转与左旋转的描述差不多,具体见下面结构图


[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. RIGHT_ROTATE(T,y)  
  2.      x = left[y]    //获取左孩子  
  3.      left[y] = right[x] //设置y的左孩子为x的右孩子  
  4.      if right[x] != NIL  
  5.         then parent[right[x]] = y  
  6.      parent[x] = parent[y]  //设为x的父节点为y的父结点  
  7.      if parent[y] == NIL  
  8.          then root = x  
  9.          else if y== left[parent[y]]  
  10.                then left[parent[y]] = x  
  11.                else  right[parent[y]] = x  
  12.      right[x] = y //设置x的右孩子为y  
  13.      parent[y] = x  

插入操作:

    红黑树的插入操作类似于二叉查找树的插入操作,只是在它的基础上进行改进,先把节点按照二叉查找树的插入方法进行插入,再把该插入的节点标记为红色(为了满足性质5),为了保证插入节点后能够维持红黑树的性质,我们必须调用一个辅助程序RB_INSERT_FIXUP来对结点重新着色并旋转,使得满足红黑树的性质。

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. RB_INSERT(T,z)  
  2.   y = NIL  
  3.   x =root(T)  
  4.   while x != NIL  
  5.        do y=x  
  6.            if key[z]<key[x]  
  7.              then x=left[x]  
  8.              else  x=right[x]  
  9.   parent[z] = y  
  10.   if y =NIL  
  11.      then root =z  
  12.      else if key[z] < key[y]  
  13.             then left[y] =z  
  14.             else  right[y] =z  
  15.    left[z] = NIL  
  16.    right[z] =NIL  
  17.    color[z] = RED  //新插入结点标记为红色  
  18.    RB_INSERT_FIXUP(T,z)  //进行调整,使得满足红黑树性质  

    插入节点后,如果会破坏红黑树的性质时,只能破坏性质2或者性质4,其他性质不会被破坏。若破坏了性质2,则新插入的节点必定为根节点,此时只需修改该节点的颜色即可。

 因为在插入新结点z之前,红黑树的性质没有被破坏。若插入结点z后违反性质4,必定是因为z和其父亲结点parent[z]都是红色的。假设新插入结点z,导致红黑树性质4被破坏,此时z和其父节点parent[z]都是红色,由于在插入结点z之前红黑树的性质没有被破坏,parent[z]是红色,很容易推出z的祖父结点parent[parent[z]]必定是黑色。
在书上有一种由上而下的程序的方法p212
假设新增节点为A,就沿着A的路径,只要看到某节点X的两个节点都为红色,将X变为红色,他的两个孩子变为黑色,之后再根据状况做一次单旋转或者双旋转进行处理就可以了

情况1:z的叔叔节点y是红色的

     此时parent[z]和y都是红色的,解决办法是将z的父节点parent[z]和叔叔结点y都着为黑色,而将z的祖父结点parent[parent[z]]着为红色,然后从祖父结点parent[parent[z]]继续向上判断是否破坏红黑树的性质。


情况2:z的叔叔节点y是黑色且z是一个右孩子

情况3:z的叔叔节点y是黑色且z是一个左孩子

操作过程类似
http://blog.csdn.net/chenhanzhun/article/details/38405041

删除操作:

    红黑树的删除操作是在二叉查找树删除的基础上进行改进,主要是因为删除节点时可能会破坏红黑树的性质。如果被删除的节点y是红色的,则删除后不会破坏红黑树的性质,既不需要修改。原因如下:

  1. 树中的黑高没有变化
  2. 不存在两个相邻的红节点
  3. 如果y是红色,就不可能是根节点,所以根节点仍然是黑色

  如果被删除的节点y是黑色,则会破坏红黑树的性质

那么就需要相应的处理过程了

0 0
原创粉丝点击