(本文主要参考与网络上一些文章加上自己的理解,代码来自JULY http://blog.csdn.net/v_JULY_v/article/details/6169600 )
在真正理解红黑树之前,我觉得它是一座难以翻越的大山;当我有点理解了它,如释重负。
看红黑树之前,我看了AVL树,觉得还是比较好理解,对于红黑树,我曾经有一些疑问:
1.为什么要用红黑来标记?
2.红黑结点如何做到平衡?
3.相对于AVL树,红黑树的优势、意义是什么呢?
在逐步学习的过程中,我大概理解了上述疑问。
首先,红黑树必须满足下面几条性质:
1. 每个结点要么是红的要么是黑的。
2. 根结点是黑的。
3. 每个叶结点(叶结点即指树尾端NIL指针或NULL结点)都是黑的。
4. 如果一个结点是红的,那么它的两个儿子都是黑的(没有连续的2个红色结点) 。
5. 对于任意结点而言,其到叶结点树尾端NIL指针的每条路径都包含相同数目的黑结点。
对于上述1,2,3属于基本规则,遵守就行了;
4,5相辅相成,是保证平衡的关键,确保了左右子树高度相差最大为"2倍"(多的那1倍都是红色结点)。
相对于AVL树,AVL树左右子树高度相差最大为"1".
关于插入
每次插入的都是红色结点。(当父结点为黑色时,不做任何操作,减少了旋转与涂色操作)
插入过程:
1.插入(必须满足BST)
2.判断是否满足红黑树性质
3.不满足,旋转,改变结点颜色
(或先改变结点颜色,再旋转,详见代码)
4.再判断是否满足性质
5.再旋转、改变结点颜色
旋转的过程与AVL是一样的,参考前一篇文章《AVL树》
关于插入改变结点颜色可以总结为下面几种情况:
当插入一个(子)结点时(插入结点为红色),
1.插入的是根结点,直接涂黑色;
2.父结点为黑色,不做任何改变;
3.父结点为红色,叔结点为红:
父结点涂黑色: uncle->color = BLACK;
叔结点涂黑色: parent->color = BLACK;
祖结点涂红色: gparent->color = RED;
(如果祖结点为根结点,再改为黑色:root->color = BLACK;)
4.父结点为红色,叔结点为黑(或NULL,NIL)
在(变换)为 根-左-左 或 根-右-右 情况下:
父结点(未来的根节点)涂黑色: parent->color = BLACK;
祖结点(未来的叔节点)涂红色:gparent->color = RED;
再右旋或左旋
关于删除
删除相对很繁琐,我的思路很简单:左侧少了一个黑结点,右侧必须“想方设法”消除一个。
删除先按照BST的方法删除结点,大概可归纳为:
1.删除结点为红色结点,直接删除,不会影响红黑树性质
2.删除结点为黑色结点(分三种情况):
1.没有子结点
以删除结点的叶子(NULL, 黑色)作为补充结点,进入: static rb_node_t* rb_erase_rebalance(rb_node_t *node, rb_node_t *parent, rb_node_t *root)
此时参数中: node 为删除结点的叶子(NULL, 黑色)
parent为删除结点的父结点
兄弟结点other = parent->right;
2.有一个子结点
以删除结点的子结点作为补充结点,进入: static rb_node_t* rb_erase_rebalance(rb_node_t *node, rb_node_t *parent, rb_node_t *root)
此时的实参为:
rb_erase_rebalance(child, parent, root);
对应的形参:node是曾经被删除结点的子结点,现在的“基准”结点,取代之前的“删除”结点
parent是曾经被删除结点的父结点,也是现在node的父结点
3.有2个子结点
将删除结点用其用右子树最小结点值取代(或用左子树最大结点值取代),
此时的“基准点”为此“取代结点” 而非“删除结点”(上述两种情况为“删除结点”)
进入: static rb_node_t* rb_erase_rebalance(rb_node_t *node, rb_node_t *parent, rb_node_t *root)
此时的实参为:
rb_erase_rebalance(child, parent, root);
child为“取代结点”的子结点
parent为“取代结点”的父结点
...
至于进入rb_erase_rebalance后如何旋转、涂色,JULY的文章中讲的很详细,我调试时纠结于这个“基准点”。
... ...
省略一大片内容,因为有些我还没有完全想清楚,后续补充一下,也可参见代码注释。
... ...
在真正理解红黑树之前,我觉得它是一座难以翻越的大山;当我有点理解了它,如释重负。
看红黑树之前,我看了AVL树,觉得还是比较好理解,对于红黑树,我曾经有一些疑问:
1.为什么要用红黑来标记?
2.红黑结点如何做到平衡?
3.相对于AVL树,红黑树的优势、意义是什么呢?
在逐步学习的过程中,我大概理解了上述疑问。
首先,红黑树必须满足下面几条性质:
1. 每个结点要么是红的要么是黑的。
2. 根结点是黑的。
3. 每个叶结点(叶结点即指树尾端NIL指针或NULL结点)都是黑的。
4. 如果一个结点是红的,那么它的两个儿子都是黑的(没有连续的2个红色结点) 。
5. 对于任意结点而言,其到叶结点树尾端NIL指针的每条路径都包含相同数目的黑结点。
对于上述1,2,3属于基本规则,遵守就行了;
4,5相辅相成,是保证平衡的关键,确保了左右子树高度相差最大为"2倍"(多的那1倍都是红色结点)。
相对于AVL树,AVL树左右子树高度相差最大为"1".
关于插入
每次插入的都是红色结点。(当父结点为黑色时,不做任何操作,减少了旋转与涂色操作)
插入过程:
1.插入(必须满足BST)
2.判断是否满足红黑树性质
3.不满足,旋转,改变结点颜色
(或先改变结点颜色,再旋转,详见代码)
4.再判断是否满足性质
5.再旋转、改变结点颜色
旋转的过程与AVL是一样的,参考前一篇文章《AVL树》
关于插入改变结点颜色可以总结为下面几种情况:
当插入一个(子)结点时(插入结点为红色),
1.插入的是根结点,直接涂黑色;
2.父结点为黑色,不做任何改变;
3.父结点为红色,叔结点为红:
父结点涂黑色: uncle->color = BLACK;
叔结点涂黑色: parent->color = BLACK;
祖结点涂红色: gparent->color = RED;
(如果祖结点为根结点,再改为黑色:root->color = BLACK;)
4.父结点为红色,叔结点为黑(或NULL,NIL)
在(变换)为 根-左-左 或 根-右-右 情况下:
父结点(未来的根节点)涂黑色: parent->color = BLACK;
祖结点(未来的叔节点)涂红色:gparent->color = RED;
再右旋或左旋
关于删除
删除相对很繁琐,我的思路很简单:左侧少了一个黑结点,右侧必须“想方设法”消除一个。
删除先按照BST的方法删除结点,大概可归纳为:
1.删除结点为红色结点,直接删除,不会影响红黑树性质
2.删除结点为黑色结点(分三种情况):
1.没有子结点
以删除结点的叶子(NULL, 黑色)作为补充结点,进入: static rb_node_t* rb_erase_rebalance(rb_node_t *node, rb_node_t *parent, rb_node_t *root)
此时参数中: node 为删除结点的叶子(NULL, 黑色)
parent为删除结点的父结点
兄弟结点other = parent->right;
2.有一个子结点
以删除结点的子结点作为补充结点,进入: static rb_node_t* rb_erase_rebalance(rb_node_t *node, rb_node_t *parent, rb_node_t *root)
此时的实参为:
rb_erase_rebalance(child, parent, root);
对应的形参:node是曾经被删除结点的子结点,现在的“基准”结点,取代之前的“删除”结点
parent是曾经被删除结点的父结点,也是现在node的父结点
3.有2个子结点
将删除结点用其用右子树最小结点值取代(或用左子树最大结点值取代),
此时的“基准点”为此“取代结点” 而非“删除结点”(上述两种情况为“删除结点”)
进入: static rb_node_t* rb_erase_rebalance(rb_node_t *node, rb_node_t *parent, rb_node_t *root)
此时的实参为:
rb_erase_rebalance(child, parent, root);
child为“取代结点”的子结点
parent为“取代结点”的父结点
...
至于进入rb_erase_rebalance后如何旋转、涂色,JULY的文章中讲的很详细,我调试时纠结于这个“基准点”。
... ...
省略一大片内容,因为有些我还没有完全想清楚,后续补充一下,也可参见代码注释。
... ...
虽然有点懂了,但是还是会忘记;理解的深度会与记忆的时间成正比。但是会让自己意识到在自己的“圈子”之外还有这么奇妙的设计。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <deque>
#include <iostream>
using namespace std;
typedef int key_t;
typedef int data_t;
typedef enum color_t
{
RED = 0,
BLACK = 1
}color_t;
typedef struct rb_node_t
{
struct rb_node_t *left, *right, *parent;
key_t key;
data_t data;
color_t color;
}rb_node_t;
static rb_node_t* rb_new_node(key_t key, data_t data)
{
rb_node_t *node = (rb_node_t*)malloc(sizeof(struct rb_node_t));
if (!node)
{
printf("malloc error!\n");
exit(-1);
}
node->key = key, node->data = data;
return node;
}
/*-----------------------------------------------------------
左旋:在 根-左-右, 根-右-右, 根-右-左的情况下都会旋转
-----------------------------------------------------------*/
static rb_node_t* rb_rotate_left(rb_node_t* node, rb_node_t* root)
{
rb_node_t* right = node->right;
if ((node->right = right->left))
{
right->left->parent = node;
}
right->left = node;
if ((right->parent = node->parent))
{
//? 根右左变为根右右后的情况下
if (node == node->parent->right)
{
node->parent->right = right;
}
//根-左-右 情况下
else
{
node->parent->left = right;
}
}
//根-右-右 根结点(顶点)被旋转情况下
else
{
root = right;
}
node->parent = right;
return root;
}
/*-----------------------------------------------------------
-----------------------------------------------------------*/
static rb_node_t* rb_rotate_right(rb_node_t* node, rb_node_t* root)
{
rb_node_t* left = node->left;
if ((node->left = left->right))
{
left->right->parent = node;
}
left->right = node;
if ((left->parent = node->parent))
{
if (node == node->parent->right)
{
node->parent->right = left;
}
else
{
node->parent->left = left;
}
}
else
{
root = left;
}
node->parent = left;
return root;
}
static rb_node_t* rb_insert_rebalance(rb_node_t *node, rb_node_t *root)
{
rb_node_t *parent, *gparent, *uncle, *tmp;
//父结点为红时进入(父结点为黑时,不用任何操作)
while ((parent = node->parent) && parent->color == RED)
{
gparent = parent->parent;
//父结点在左
if (parent == gparent->left)
{
uncle = gparent->right;
//叔结点为红
if (uncle && uncle->color == RED)
{
uncle->color = BLACK;
parent->color = BLACK;
gparent->color = RED;
node = gparent;
}
//叔结点为黑
else
{
//根-左-右结构
if (parent->right == node)
{
root = rb_rotate_left(parent, root);
tmp = parent;
parent = node;
node = tmp;
}
//根-左-左结构(根-左-右结构 经过左旋后)
parent->color = BLACK;
gparent->color = RED;
root = rb_rotate_right(gparent, root);
}
}
//父结点在右
else
{
uncle = gparent->left;
//叔结点为红,涂色和上面一样
if (uncle && uncle->color == RED)
{
uncle->color = BLACK;
parent->color = BLACK;
gparent->color = RED;
node = gparent;
}
//叔结点为黑
else
{
//根-右-左结构
if (parent->left == node)
{
root = rb_rotate_right(parent, root);
tmp = parent;
parent = node;
node = tmp;
}
//根-右-右结构(根-右-左结构 经过右旋后)
parent->color = BLACK;
gparent->color = RED;
root = rb_rotate_left(gparent, root);
}
}
}
root->color = BLACK;
return root;
}
//parent是曾经被删除(取代)的父结点
//node是曾经被删除(取代)的子结点,现在的“目标”结点,取代之前的“目标”结点
//最多可能发生3次旋转
static rb_node_t* rb_erase_rebalance(rb_node_t *node, rb_node_t *parent, rb_node_t *root)
{
rb_node_t *other, *o_left, *o_right;
//node结点为NULL或为黑色,且不是根节点
while ((!node || node->color == BLACK) && node != root)
{
//node为左子结点
if (parent->left == node)
{
//other为兄弟结点
other = parent->right;
//兄弟结点为红
if (other->color == RED)
{
other->color = BLACK;
parent->color = RED;
root = rb_rotate_left(parent, root);
other = parent->right;
}
//兄弟结点为黑,兄弟结点的左右子树为空或都是黑色的
if ((!other->left || other->left->color == BLACK) &&
(!other->right || other->right->color == BLACK))
{
other->color = RED;
//node结点和parent结点会向上移动,如果调整没有结束会继续调整
node = parent;
parent = node->parent;
}
//兄弟结点为黑,兄弟的子结点待定
else
{
//兄弟的右子结点为NULL 或 为黑色(兄弟的左子树为红,上一级if已经排除了黑色或NULL)
if (!other->right || other->right->color == BLACK)
{
//如果兄弟的左子结点有值,涂为黑色
if ((o_left = other->left))
{
o_left->color = BLACK;
}
//兄弟结点涂为红色
other->color = RED;
root = rb_rotate_right(other, root);
other = parent->right;
}
//兄弟的右子结点为红色 (兄弟的左子结点为红色?)
other->color = parent->color;
parent->color = BLACK;
if (other->right)
{
other->right->color = BLACK;
}
root = rb_rotate_left(parent, root);
node = root;
break;
}
}
else
{
other = parent->left;
if (other->color == RED)
{
other->color = BLACK;
parent->color = RED;
root = rb_rotate_right(parent, root);
other = parent->left;
}
if ((!other->left || other->left->color == BLACK) &&
(!other->right || other->right->color == BLACK))
{
other->color = RED;
node = parent;
parent = node->parent;
}
else
{
if (!other->left || other->left->color == BLACK)
{
if ((o_right = other->right))
{
o_right->color = BLACK;
}
other->color = RED;
root = rb_rotate_left(other, root);
other = parent->left;
}
other->color = parent->color;
parent->color = BLACK;
if (other->left)
{
other->left->color = BLACK;
}
root = rb_rotate_right(parent, root);
node = root;
break;
}
}
}
if (node)
{
node->color = BLACK;
}
return root;
}
//save: 新(搜索)结点的parent return: 搜索到的结点指针
static rb_node_t* rb_search_auxiliary(key_t key, rb_node_t* root, rb_node_t** save)
{
rb_node_t *node = root, *parent = NULL;
int ret;
while (node)
{
parent = node;
ret = node->key - key;
if (0 < ret)
{
node = node->left;
}
else if (0 > ret)
{
node = node->right;
}
else
{
return node;
}
}
if (save)
{
*save = parent;
}
return NULL;
}
rb_node_t* rb_insert(key_t key, data_t data, rb_node_t* root)
{
//parent: 新加入结点的parent; node: 新的结点
rb_node_t *parent = NULL, *node;
parent = NULL;
//取得新加入结点的parent;root值不会变
if ((node = rb_search_auxiliary(key, root, &parent)))
{
return root;
}
//对新结点赋值,插入(attach)
node = rb_new_node(key, data);
node->parent = parent;
node->left = node->right = NULL;
node->color = RED;
if (parent)
{
if (parent->key > key)
{
parent->left = node;
}
else
{
parent->right = node;
}
}
else
{
root = node;
}
return rb_insert_rebalance(node, root);
}
rb_node_t* rb_search(key_t key, rb_node_t* root)
{
return rb_search_auxiliary(key, root, NULL);
}
rb_node_t* rb_erase(key_t key, rb_node_t *root)
{
rb_node_t *child, *parent, *old, *left, *node;
color_t color;
if (!(node = rb_search_auxiliary(key, root, NULL)))
{
printf("key %d is not exist!\n");
return root;
}
old = node;
if (node->left && node->right)
{
node = node->right;
//找到node右子树的最小值
while ((left = node->left) != NULL)
{
node = left;
}
//替代值(将替代删除结点) 赋值 给child,parent,color
child = node->right;
parent = node->parent;
color = node->color;
if (child)
{
child->parent = parent;
}
//清除"取代值"
if (parent)
{
if (parent->left == node)
{
parent->left = child;
}
else
{
parent->right = child;
}
}
else
{
root = child;
}
if (node->parent == old)
{
parent = node;
}
//(完全)取代
node->parent = old->parent;
node->color = old->color;
node->right = old->right;
node->left = old->left;
if (old->parent)
{
if (old->parent->left == old)
{
old->parent->left = node;
}
else
{
old->parent->right = node;
}
}
else
{
root = node;
}
//原左子树建立与新结点链接
old->left->parent = node;
if (old->right)
{
old->right->parent = node;
}
}
else
{
if (!node->left)
{
child = node->right;
}
else if (!node->right)
{
child = node->left;
}
parent = node->parent;
color = node->color;
if (child)
{
child->parent = parent;
}
if (parent)
{
if (parent->left == node)
{
parent->left = child;
}
else
{
parent->right = child;
}
}
else
{
root = child;
}
}
free(old);
if (color == BLACK)
{
root = rb_erase_rebalance(child, parent, root);
}
return root;
}
void level_traverse(rb_node_t* root)
{
if(root == NULL)
{
return;
}
deque<rb_node_t *> dequesTree;
dequesTree.push_back(root);
while(dequesTree.size())
{
rb_node_t *p = dequesTree.front();
dequesTree.pop_front();
cout << (p->key)<<" ";
if(p->left)
{
dequesTree.push_back(p->left);
}
if(p->right)
{
dequesTree.push_back(p->right);
}
}
cout<<endl;
}
int main()
{
int i, count = 90;
key_t key;
rb_node_t* root = NULL, *node = NULL;
srand(time(NULL));
int array[] = {16,3,7,11,9,26,18,14,15,17};
//for (i = 1; i < count; ++i)
for (i = 0; i < 10; ++i)
{
root = rb_insert(array[i], i, root);
/*
key = rand() % count;
if ((root = rb_insert(key, i, root)))
{
printf("[i = %d] insert key %d success!\n", i, key);
}
else
{
printf("[i = %d] insert key %d error!\n", i, key);
exit(-1);
}
if ((node = rb_search(key, root)))
{
printf("[i = %d] search key %d success!\n", i, key);
}
else
{
printf("[i = %d] search key %d error!\n", i, key);
exit(-1);
}
if (!(i % 10))
{
if ((root = rb_erase(key, root)))
{
printf("[i = %d] erase key %d success\n", i, key);
}
else
{
printf("[i = %d] erase key %d error\n", i, key);
}
}
*/
}
level_traverse(root);
/*
for (i = 0; i < 10; ++i)
{
root = rb_erase(array[i],root);
}
*/
root = rb_erase(3,root); //将发生3次旋转
level_traverse(root);
return 0;
}