# 二、历史

The original data structure was invented in 1972 by Rudolf Bayer[2] and named "symmetric binary B-tree," but acquired its modern name in a paper in 1978 byLeonidas J. Guibas and Robert Sedgewick entitled "A Dichromatic Framework for Balanced Trees".[3] The color "red" was chosen because it was the best-looking color produced by the color laser printer available to the authors while working at Xerox PARC.[4]

# 三、术语

A red–black tree is a special type of binary tree, used in computer science to organize pieces of comparable data, such as text fragments or numbers.

The leaf nodes of red–black trees do not contain data. These leaves need not be explicit in computer memory—a null child pointer can encode the fact that this child is a leaf—but it simplifies some algorithms for operating on red–black trees if the leaves really are explicit nodes. To save memory, sometimes a singlesentinel node performs the role of all leaf nodes; all references from internal nodes to leaf nodes then point to the sentinel node.

Red–black trees, like all binary search trees, allow efficient in-order traversal (that is: in the order Left–Root–Right) of their elements. The search-time results from the traversal from root to leaf, and therefore a balanced tree of n nodes, having the least possible tree height, results in O(log n) search time.

# 四、性质

1. 节点必须是红色或者黑色。
2. 根节点必须是黑色。
3. 叶节点(NIL)是黑色的。（NIL节点无数据，是空节点）
4. 红色节点必须有两个黑色儿子节点。
5. 从任一节点出发到其每个叶子节点的路径，黑色节点的数量是相等的。

# 五、类比四阶的B树

4阶B树与红黑树的对应转换关系（图片引用自LLRB）：

• B树的节点簇有一个Key值，包含两个子节点指针；对应红黑树中的一个黑色节点。

• B树的节点簇有三个Key值，包含四个子节点指针；中键对应红黑树中的黑色节点，左右键为中键的红色子节点。

• B树的节点簇有三个Key值，包含四个子节点指针；中键对应红黑树中的黑色节点，左右键为中键的红色子节点。

# 五、操作

### 1.插入

• 性质3（所有的叶子节点都是黑色）不会被破坏，因为叶子节点全部是黑色的NIL。
• 性质4（红色节点的两个儿子必须是黑色）仅在添加一个红色节点时，将黑色节点染成红色时，或者进行旋转操作时发生改变。
• 性质5（从任一节点出发到叶子节点的路径中黑色节点的数量相等）仅在添加黑色节点时，将红色节点染成黑色时，或者进行旋转操作时发生改变。

struct node *grandparent(struct node *n)
{
if ((n != NULL) && (n->parent != NULL))
return n->parent->parent;
else
return NULL;
}struct node *uncle(struct node *n)
{
struct node *g = grandparent(n);
if (g == NULL)
return NULL; // No grandparent means no uncle
if (n->parent == g->left)
return g->right;
else
return g->left;
}

Case1：当前节点N是树中的根节点的情况。这时，将节点直接染成黑色以满足性质2（根节点是黑色）。

void insert_case1(struct node *n)
{
if (n->parent == NULL)
n->color = BLACK;
else
insert_case2(n);
}


Case2：当前节点的父亲P是黑色的情况。这时，性质4（红色节点必须有两个黑色儿子节点）不会被破坏。性质5（从任一节点出发到其每个叶子节点的路径，黑色节点的数量是相等的）也仍然满足，因为节点N是红色，但N还有两个黑色的叶子节点NIL，所有通过N的路径上，仍然保持和原来相同的黑色节点个数。

void insert_case2(struct node *n)
{
if (n->parent->color == BLACK)
return; /* Tree is still valid */
else
insert_case3(n);
}


Case3：当前节点的父亲P和叔叔U都是红色的情况。这时，将P、U都染成黑色，而G染成红色以满足性质5（从任一节点出发到其每个叶子节点的路径，黑色节点的数量是相等的）。现在，当前的红色节点N有一个黑色的父亲，而且所有经过父亲和叔叔节点的路径仍然保持与原来相同的节点个数。但是爷爷节点G可能会违反性质2（根节点必须是黑色）或者性质4（红色节点必须有两个黑色儿子节点）（在G节点的父亲也是红色节点时，会破坏性质4）。要修复这个问题，可以对节点G递归执行Case1的操作（可以这样理解，把G当作是新插入的红色节点，对G执行调整操作。因为G的两个子树是平衡的）。这里是尾递归调用，所以也可以使用循环的方法实现。因为这之后肯定会执行一次旋转操作，而且肯定提常数级的旋转次数。

void insert_case3(struct node *n)
{
struct node *u = uncle(n), *g;

if ((u != NULL) && (u->color == RED)) {
n->parent->color = BLACK;
u->color = BLACK;
g = grandparent(n);
g->color = RED;
insert_case1(g);
} else {
insert_case4(n);
}
}


Case4：父亲P是红色，叔叔U是黑色，并且N是P的右孩子，P是G的左孩子的情况。

Case4的主要目的就是将当前情况转换到Case5进行处理。

Case4的说明和图示中，我们仅提到了N是右孩子，P是左孩子的情况；另外N是左孩子，P是右孩子的情况没有说明。因为这两种情况处理方法是相似的。不过在C代码中包括了两种情况的处理。

void insert_case4(struct node *n)
{
struct node *g = grandparent(n);

if ((n == n->parent->right) && (n->parent == g->left)) {
rotate_left(n->parent);

/*
* rotate_left can be the below because of already having *g =  grandparent(n)
*
* struct node *saved_p=g->left, *saved_left_n=n->left;
* g->left=n;
* n->left=saved_p;
* saved_p->right=saved_left_n;
*
* and modify the parent's nodes properly
*/

n = n->left;

} else if ((n == n->parent->left) && (n->parent == g->right)) {
rotate_right(n->parent);

/*
* rotate_right can be the below to take advantage of already having *g =  grandparent(n)
*
* struct node *saved_p=g->right, *saved_right_n=n->right;
* g->right=n;
* n->right=saved_p;
* saved_p->left=saved_right_n;
*
*/

n = n->right;
}
insert_case5(n);
}


Case5：父亲P是红色，但叔叔U是黑色， N是左孩子，P也是左孩子的情况。

void insert_case5(struct node *n)
{
struct node *g = grandparent(n);

n->parent->color = BLACK;
g->color = RED;
if (n == n->parent->left)
rotate_right(g);
else
rotate_left(g);
}

### 2.删除

struct node *sibling(struct node *n)
{
if (n == n->parent->left)
return n->parent->right;
else
return n->parent->left;
}

Note: In order that the tree remains well-defined, we need that every null leaf remains a leaf after all transformations (that it will not have any children). If the node we are deleting has a non-leaf (non-null) child N, it is easy to see that the property is satisfied. If, on the other hand, N would be a null leaf, it can be verified from the diagrams (or code) for all the cases that the property is satisfied as well.

void delete_one_child(struct node *n)
{
/*
* Precondition: n has at most one non-null child.
*/
struct node *child = is_leaf(n->right) ? n->left : n->right;

replace_node(n, child);
if (n->color == BLACK) {
if (child->color == RED)
child->color = BLACK;
else
delete_case1(child);
}
free(n);
}

Note
: If N is a null leaf and we do not want to represent null leaves as actual node objects, we can modify the algorithm by first calling delete_case1() on its parent (the node that we delete, n in the code above) and deleting it afterwards. We can do this because the parent is black, so it behaves in the same way as a null leaf (and is sometimes called a 'phantom' leaf). And we can safely delete it at the end as n will remain a leaf after all operations, as shown above.

Case1：N是根节点。此时什么也不需要做。因为每条路径都少了一个黑色节点，而且根是黑色的，所以所有性质都没有被破坏。

void delete_case1(struct node *n)
{
if (n->parent != NULL)
delete_case2(n);
}

Case2：S是红色。

void delete_case2(struct node *n)
{
struct node *s = sibling(n);

if (s->color == RED) {
n->parent->color = RED;
s->color = BLACK;
if (n == n->parent->left)
rotate_left(n->parent);
else
rotate_right(n->parent);
}
delete_case3(n);
}

Case3：P、S和S的儿子都是黑色的情况。

void delete_case3(struct node *n)
{
struct node *s = sibling(n);

if ((n->parent->color == BLACK) &&
(s->color == BLACK) &&
(s->left->color == BLACK) &&
(s->right->color == BLACK)) {
s->color = RED;
delete_case1(n->parent);
} else
delete_case4(n);
}

Case4：S和S的儿子是黑色，但P是红色的情况。

void delete_case4(struct node *n)
{
struct node *s = sibling(n);

if ((n->parent->color == RED) &&
(s->color == BLACK) &&
(s->left->color == BLACK) &&
(s->right->color == BLACK)) {
s->color = RED;
n->parent->color = BLACK;
} else
delete_case5(n);
}


Case5：P点颜色任意，S点是黑色，S左儿子是红色，右儿子是黑色。N是P的左儿子（S是P的右儿子）的情况。

void delete_case5(struct node *n)
{
struct node *s = sibling(n);

if  (s->color == BLACK) { /* this if statement is trivial,
due to case 2 (even though case 2 changed the sibling to a sibling's child,
the sibling's child can't be red, since no red parent can have a red child). */
/* the following statements just force the red to be on the left of the left of the parent,
or right of the right, so case six will rotate correctly. */
if ((n == n->parent->left) &&
(s->right->color == BLACK) &&
(s->left->color == RED)) { /* this last test is trivial too due to cases 2-4. */
s->color = RED;
s->left->color = BLACK;
rotate_right(s);
} else if ((n == n->parent->right) &&
(s->left->color == BLACK) &&
(s->right->color == RED)) {/* this last test is trivial too due to cases 2-4. */
s->color = RED;
s->right->color = BLACK;
rotate_left(s);
}
}
delete_case6(n);
}

Case6：P点颜色任意，S点是黑色，S的右儿子是红色。N是P的左儿子（S是P的右儿子）的情况。

• 经过N的新兄弟SL（即图中标为3的子树）的路径。无论是调整前，还是调整后，经过SL点的路径都会经过S点和P点。因为调整操作仅仅是将P、S互换的颜色和位置，所以这条路径中黑色节点的数量没有变化。
• 经过N的新叔叔SR（S的右儿子,现在为黑色）的路径。调整前，此路径会经过红色的SR、黑色的S及颜色未知的P（取S的父亲）。调整后，此路径仅经过黑色的SR（由红色染成黑色）、颜色未知的S（与P互换颜色）。因为路径长度仅计算黑色节点，所以这条路径中黑色节点数量没有变化。

void delete_case6(struct node *n)
{
struct node *s = sibling(n);

s->color = n->parent->color;
n->parent->color = BLACK;

if (n == n->parent->left) {
s->right->color = BLACK;
rotate_left(n->parent);
} else {
s->left->color = BLACK;
rotate_right(n->parent);
}
}


# 六、参考

http://www.cs.princeton.edu/~rs/talks/LLRB/RedBlack.pdf

http://en.wikipedia.org/wiki/Red%E2%80%93black_tree

https://www.cs.usfca.edu/~galles/visualization/RedBlack.html

posted @ 2014-09-01 14:15  hi.low  阅读(24678)  评论(3编辑  收藏  举报