本文主要参考 Mark Allen Weiss 的 Data Structures and Algorithn Analysis in Java (Second Edition) 的中译本,对其中省略的地方进行了补充。
什么是红黑树?
红黑树本质上是二叉查找树,但增加了一些性质,使这种二叉查找树更加平衡,使得对其操作最坏情况花费O(logN):
1) 每一个节点或者为红,或者为黑;
2) 根为黑;
3) 如果一个节点为红,它的孩子必为黑(约定null为黑);
4) 从一个节点到一个null引用的每一条路径必须包含相同数目的黑色节点。
推论:
1) 由性质3)和性质4),最长路径至多为最短路径2倍(最短路径为全黑,最长路径为红黑相间);
2) 由推论1),红黑数高度最多为2log(N+1)。
红黑树的操作
和二叉查找树一样,红黑书的基本操作是查找,插入,删除。
查找和二叉查找树一样。
插入和删除由于可能破坏红黑树性质,则比较特殊。
插入
为了满足性质4),插入的新节点必须为红色。
自底向上的插入
1)根据二叉查找性质,首先找到插入点;
2)若父节点为黑色,插入完成;
3)若父节点为红色
a. 父节点的兄弟为黑。
规定新插入节点为X,父节点为P,叔父节点为S,祖父节点为G,双圈红,单圈黑。此时只可能X和P为红。
则X,P,G可能为一字形或之字形,对其
进行一型旋转(单旋转)或之型旋转(双旋转),
得到的新根涂黑,新根的两个儿子涂红,
完成
b. 父节点的兄弟为红
(旋转之后)新根和S涂红,G和另外一个节点涂黑
若曾祖节点为红,则产生新的两红相连,继续上滤,直到没有两红相连,或者到达根(根被重新涂黑)。
需要注意的是,在具体编程中,自底向上的操作都是需要节点保留父引用(指针)的。
自顶向下插入
自顶向下的插入在寻找插入点的过程中对树进行调整,保证S不会为红。
查找过程中:
1) 当前节点X有两个红儿子,则让X变红,两儿子变黑(若X为根,则变红之后再变黑)
此时,若X的父节点为红,则出现两红相连,但可以证明,X的叔父节点不可能为红,则进行一次旋转和变色即可。
2) 其他情况继续向下遍历。
3) 找到插入点插入即可。
删除
删除也分为自底向上和自顶向下。
自底向上的删除可以参考《算法导论》,由于情况太多,《算法导论》实际上没有讲清楚,July花了6篇博文来阐述,有兴趣可以参考http://blog.csdn.net/v_JULY_v/article/details/6105630
自顶向下删除
自顶向下的删除,Weiss的书没有讲清楚,这里简单翻译一篇英文http://www2.ee.ntu.edu.tw/~yen/courses/ds-03/Red-Black-Trees-top-down-deletion.pdf
准备步骤:
将问题归结为删除树叶
1)带有两个儿子的节点,用右子树最小节点代替(将右子树最小节点内容放入此节点),删除该最小节点(此节点必然最多有一个儿子);
2)带有一个右儿子(右子树),以1)方式删除
3)带有一个左儿子(左子树),用左子树最大节点代替(将左字数最大节点内容放入此节点),删除该最大节点。
过程:
(X为当前节点,T为X兄弟,P为X父节点)
step 1: 检查root
1. 如果root两个children都为黑
a. root变红
b. X指向搜索路径上root的child
c. 转到step2
2. 否则, X指向root,转到step2B
step2:
2A1: X有两个黑儿子, T也有两个黑儿子。 反转X,P,T颜色
2A2: X有两个黑儿子,T的左儿子为红。 L,T,P进行双旋转(之字形旋转), X, P变色
2A3: X有两个黑儿子,T的右儿子为红。 R,T,P单旋转(一字形旋转), X,P,T,R都变色
2B:
a. 继续向下
b. 如果新X为红,继续向下
c. 如果新X为黑,(必有T为红,P为黑),单旋转T,P,同时,T,P变色
d. 回到step2.
step3
最终找到要删除节点,这是一个叶节点,将节点以红节点身份删除
step4
最后将root染成黑色。
完