红黑树

来源:互联网 发布:linux vim 退出命令 编辑:程序博客网 时间:2024/06/06 23:54

本文内容主要参考并基于《算法导论》第二版

引言

本文对红黑树的几个关键的知识点进行介绍,包括:

1)红黑树的定义

2)如何增删结点

 

红黑树的定义

红黑树是一种满足以下性质的二叉查找树:

1)所有的结点要么是红色的,要么是黑色的

2)根结点是黑色的

3)叶子结点是黑色的

4)如果一个结点是红色的,则它的两个孩子都是黑色的

5)对于一个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点

需要注意的是,红黑树首先是一棵二叉查找树,即它要满足二叉查找树的所有性质。红黑树还有一个比较常用的概念——黑高度,具体定义可查阅相关资料。

 

如何增删结点

一、首先需要理解增删结点要用到两个常用操作:左旋和右旋

如上图,从左到右是对x左旋——LEFT-ROTATE(T,x),从右到左是对y右旋——RIGHT-ROTATE(T,y)

理解左旋和右旋的一个关键点要知道操作的对象,严格来讲,单说左旋(右旋)是不对的,完整的说法应该是对某某左旋(右旋)。所以,对x左旋,是指把x和x的右孩子逆时针旋转;对x右旋,是指把x和x的左孩子顺时针旋转。

代码实现的时候需要注意,对每个结点,它的三个关键指针——父指针、左孩子、右孩子是否都已经正确处理。

另外需要注意的是,对红黑树的旋转不会改变结点的颜色。

 

二、插入结点

总的来说,插入结点分为三步(插入、着色、调整):

1)按照查找二叉树中插入结点的方法把新增的结点插入红黑树中

2)把新插入的结点着为红色

3)新插入的结点有可能破坏红黑树的5个性质,所以需要对此进行调整。

《算法导论》中把第三步叫做RB-INSERT-FIXUP(T, z) 。在这一步,算法会根据一些条件把结点z的状态分为三种情况,对每种情况做出不同的操作(改变颜色、左旋、右旋),直到满足红黑树的5个性质。其伪代码如下:

RB-INSERT-FIXUP(T, z) 1 while color[p[z]] = RED 2     do if p[z] = left[p[p[z]]] 3           then y ← right[p[p[z]]] 4                if color[y] = RED 5                   then color[p[z]] ← BLACK                    ▹ Case 1 6                        color[y] ← BLACK                       ▹ Case 1 7                        color[p[p[z]]] ← RED                   ▹ Case 1 8                        z ← p[p[z]]                            ▹ Case 1 9                   else if z = right[p[z]]10                           then z ← p[z]                       ▹ Case 211                                LEFT-ROTATE(T, z)              ▹ Case 212                           color[p[z]] ← BLACK                 ▹ Case 313                           color[p[p[z]]] ← RED                ▹ Case 314                           RIGHT-ROTATE(T, p[p[z]])            ▹ Case 315           else (same as then clause                         with "right" and "left" exchanged)16 color[root[T]] ← BLACK

对这段代码的理解要注意以下几点:

1)z始终指向红节点

2)z的父结点是红节点

3)3种情况的划分取决于:

   a. z的叔叔结点的颜色

   b. z是左孩子还是右孩子

4)左旋或右旋操作不会改变结点的颜色

5)代码的第2至14行的前提是z的父结点是左结点

以下是对三种情况的说明:

case1:z的叔叔y是红色的

case2:z的叔叔y是黑色的,且z是右孩子

case3:z的叔叔y是黑色的,且z是左孩子

由于z的父结点是左结点,所以要把case2向case3变换,当z的父结点是右结点时,就应该是把case3向case2变换。

 

三、删除结点

0 0