红黑树是工程中用的比较多的一个数据结构,它的优点是查找的复杂度是O(lgN), 而且红黑树会在插入
数据的时候保持平衡,抑制复杂度的暴涨。虽然它没有hashtable那样高效,但是不用事先规划并分配空间。那么它是怎么做到的呢?
下面是它的特性:
1.红黑树由红色和黑色的元素构成(着色)
2.红色节点没有红色的子节点(红色与红色是宿敌)
3.所有从根节点到叶子节点的黑色节点数量相等(左右平衡)。
可以推出:
1根节点是黑色的。
2.红色节点的两个子节点都是黑色的
插入操作
数据是怎么插入呢?这里忘了提它的一个重要的性质,中间的数据总比左边的大, 比右边的小。
这样可以保证查找时沿着一条路下去找就可以了。
这里举个例子:


插入步骤
1.比当前键值小的,往左移,比当前键值大的,往右移动。找适当位置插入
2.颜色的决定
——如果把它搞成黑色,那么就比较麻烦了,因为所有从根节点到叶子节点的黑色节点数量相等。
这样一来会比较难以修复。
——所以搞成红色
3.红色的点插入后会导致两个红色的点连续的情况,违反了红色节点没有红色的子节点的条件。
所以我们要在插入后进行修复。这是红黑树比较麻烦的点。
注意点
修复时,空的子节点也要带上一起修复(被认为是黑色)!
修复时,把红色的节点往上拉,可以减少冲突!
2-3树
关于红黑树的操作,可以先看看2-3树是怎么操作的,这样可以容易理解红黑树的操作。
具体可以看看算法这本书,作者是(Robert Sedgewick 和Kevin Wayne),英文原版424页。
这里是其中的一张图(重画),可以看到,单个key的设计可以用多key的节点演化而来。



原书446页有这样一句话,可以说明红黑树是从2-3树演化而来的。所以看懂了2-3树之后,红黑树也就容易理解了。
The basic idea behind red-black BSTs is to encode 2-3 trees by starting with standard BSTs (which are made up of 2-nodes) and adding extra information to encode 3-nodes.
红黑树这样的形态,即获得了BST的简易性,又获得了2-3树的平衡性,红黑树是2-3树的一种特殊的形态。
2-3树到红黑树的转换:



这里的红黑点实际上是红黑的链接,图中红色粗链接表明红线下面的节点是红色的。

红黑树操作
左右两图进行了rotate操作(左旋和右旋),但是它们是等价的,因为数据的顺序是不变的(BCDEF)。
只是将红色链接倾斜了。




红黑树插入
第一个点是黑色的。
插入第二个点,一定在它的左边或者右边。在左边的时候直接在左边插入一个红点就行了。
在右边的时候插入一个红点,并且做左旋操作。在这里,作者基本上都尽量将节点左旋。
这是总结出的做法:
left rotate, right rotate, and color flip
总的来说,先尽量将红色链接放到左边,当连续有两个左边的红色链接时,做右旋,使得它左右两边都有红色链接。最后将这个两个链接变成黑色。



红黑树的删除
删除会比较麻烦一点,但是如果将它看成2-3树就好多了:

举个例子,若要将A删除,只要将ABC合并成一组再删除,这样就不用考虑链接的处理了。
这里书上都有讲。


参考文献:
Algorithms - fourth edition
http://www.cs.usfca.edu/~galles/visualization/RedBlack.html