红黑树

AVL-tree、RB-tree、AA-tree均可以实现平衡的二叉查找树,虽然相对于一般的二叉搜索树其插入、删除节点的平均时间会比较长,但它们可以避免极验证应付的最坏的情况--树高度不平衡。

平衡二叉查找树所谓的平衡并不是绝对的平衡,而是要求任何一个节点的左右子树高度相差不会超过1,此时仍能够保证树的“对数深度”。

在学习红黑树之前要先学习AVL树,了解一些旋转操作是怎么进行的。

 

红黑树_第1张图片

如上图所示,X节点本来是平衡的,插入一个新节点后“平衡被破坏”了,这可以分为4种情况:

  1. 插入节点位于X的左子节点的左子树--左左;
  2. 插入节点位于X的左子节点的右子树--左右;
  3. 插入节点位于X的右子节点的左子树--右左;
  4. 插入节点位于X的右子节点的右子树--右右。

情况1、4彼此对称,称为外侧插入,可以采用单旋操作调整解决;情况2、3彼此对称,称为内侧插入,可以采用双旋转操作调整解决。

单旋转

红黑树_第2张图片

插入新节点11出现情况1的调整策略:把中k1作为其左子孩子k2的右孩子,而k2原先的右孩子作为现在k1的左孩子。

出现情况4的调整策略类同。

双旋转

 

红黑树_第3张图片

插入新节点15出现情况2的调整策略:先让k2和k1做一次单旋转,再让k2和k3做一次单旋转。

出现情况3的调整策略类同。

红黑树RB-tree

C++中的set和map底层用的就是红黑树。

RB-tree是满足以下4个条件的二叉查找树:

  1. 每个节点不是红色就是黑色
  2. 根节点为黑色
  3. 红节点的子节点必须是黑色
  4. 任一节点至NULL(树尾端)的每一条路径上,所含黑节点的数目必须相同

红黑树并不要求左右子树高度差控制在1以内,它的平衡条件比AVL树弱。然而红黑树通常能够导致良好的平衡状态,经验告诉我们,红黑树的平均搜索效率和AV-tree几乎相等,但是其插入节点的开销相对较低,实践中发生旋转的次数相对较少。

以下所有操作,在新插入节点后,首先将新节点设为红色。

按照二叉查找树的规则插入新节点后,如果新增节点的父节点为黑,则直接插入。否则分为4种情况(在此作一些符号约定,新增节点为X,其父节点为P,祖父节点为G,伯父节点为S,曾祖父节点为GG):

红黑树_第4张图片

  1. S为黑,且X为外侧插入。P,G做一次单旋转,并更改P,G的颜色。
  2. S为黑,且X为内侧插入。 X,P做一次单旋转,并更改X和P的颜色。再对X,G做一次单旋转。
  3. S为红,且X为外侧插入。 P,G做一次单旋转,并更改X的颜色。此时如果GG为黑,一切搞定;否则,还得继续往上做,直到不再有父子节点连续为红的情况。
  4.  S为红,且X为内侧插入。直接更改P,S,G的颜色。此时如果GG为黑,一切搞定;否则,还得继续往上做,直到不再有父子节点连续为红的情况。

为了避免上述情况3、4中GG也为红的情况发生,我们设计一个“自顶向下”的红黑树。假设新增节点为A,那么就延着从根节点到A的路径,只要看到某个节点X的两个子节点皆为红色,就把这两个子节点改为黑色,同时把X改为红色。但是如果此时X的父节点也是红色(注意此时X的伯父节点已经不可能是红色),就像上述情况1那样作一次单旋转改变颜色,或像情况2那样做一些双旋转再改变颜色。

你可能感兴趣的:(红黑树)