红黑树学习记录
来源:互联网 发布:国家级新区经济数据 编辑:程序博客网 时间:2024/05/21 21:04
这段时间,天天解bug,搞的整个人都烦死了。突然,对红黑树的实现来了兴趣,就费了3天的功夫,自己作了一个,虽然很简单,但实现起来,还真要费点劲。
红黑树的性质很简单,要满足以下5条。
1) 每个节点必须是红色或者是黑色的;
2) 所有的叶子节点的颜色都是黑色的;
3) 如果有一个节点颜色是红色的,那么它的儿子节点颜色是黑的,它的父亲节点颜色也是黑的;
4) 任一节点到该节点上的叶子的所有简单路径上的黑色节点的个数是相同的;
5) 根节点的颜色是黑色的;
在红黑树的操作中,左旋和右旋是比较常用的操作。实现如下:
/*
下面的操作叫左旋操作,可以这样记忆: 在P1的子树下,最终B成为根,代替了A,所以,所谓左旋是针对B的方向来称呼的。以下右旋雷同;因为是A树下的左旋,左边旋转是对B来讲,所以B必是A的右孩子;
p1 p2
| |
| |
( A ) ( B )
/ / / /
/ / LR / /
a ( B ) =======> (A) c
/ / / /
/ / / /
b c a b
*/
void LeftRotate(PNODE* root, PNODE A)
{
PNODE B = A->right;
if (B == LEAF)
{
return;
}
A->right = B->left;
if (B->left != LEAF)
{
(B->left)->parent = A;
}
B->parent = A->parent;
if (A == *root)
{
*root = B;
}
else if (A == ((A->parent)->left))
{
A->parent->left = B;
}
else
{
A->parent->right = B;
}
B->left = A;
A->parent = B;
}
/*
下面是右旋函数,与上面的函数相对应;
| |
| |
( A ) ( B )
/ / / /
/ / RR / /
( B ) a =======> b ( A )
/ / / /
/ / / /
b c c a
*/
void RightRotate(PNODE* root, PNODE A)
{
PNODE B = A->left;
if (B == LEAF)
{
return;
}
A->left = B->right;
if (B->right != LEAF)
{
(B->right)->parent = A;
}
B->parent = A->parent;
if (A == *root)
{
*root = B;
}
else if (A == ((A->parent)->left))
{
(A->parent)->left = B;
}
else
{
(A->parent)->right = B;
}
B->right = A;
A->parent = B;
}
一下是详细的代码和注释:
/*
* 颜色的枚举类型
*/
enum COLOR
{
RED = 0,
BLACK
};
/*
* 简单的定义一下数据结构
*/
#define ELEMENT int
/*
* 节点的数据结构
*/
typedef struct TAG_NODE
{
TAG_NODE* parent;
TAG_NODE* left;
TAG_NODE* right;
COLOR color;
ELEMENT key;
} NODE, *PNODE;
/*
* 实现对树的非递归遍历是利用的虚拟栈数据结构
*/
typedef struct TAG_SQ
{
PNODE data[2048];
int index; /* from 1 - 2047 */
int size; /* the max size = 2047 */
} SQ, *PSQ;
#define LEAF ((PNODE)0)
#define INT32 int
#define Parent(x) ((x)->parent)
#define Grand(x) ( ((x) ->parent)->parent)
#define Brother(x) ( ( (x) == ( (x)->parent->left) ) ? ( (x)->parent->right) : ( (x)->parent->left) )
#define Uncle(x) Brother( (Parent(x) ) )
/*
* 此宏默认叶子节点的颜色是黑色
*/
#define GetColor(x) ((x) == LEAF ? BLACK : (x)->color)
void LeftRotate(PNODE* root, PNODE A);
void RightRotate(PNODE* root, PNODE A);
PNODE FindNode(PNODE* root, ELEMENT key);
PNODE FindNextNode(PNODE* root, ELEMENT key, PNODE start);
PNODE InsertNode(PNODE* root, ELEMENT key);
PNODE DeleteNode(PNODE* root, ELEMENT key);
PNODE FixupTreeByInsert(PNODE* root, PNODE z);
void FixupTreeByDelete(PNODE* root, PNODE z);
/*
* 保存红黑树的根节点
*/
PNODE root = LEAF;
void LeftRotate(PNODE* root, PNODE A)
{
PNODE B = A->right;
if (B == LEAF)
{
return;
}
A->right = B->left;
if (B->left != LEAF)
{
(B->left)->parent = A;
}
B->parent = A->parent;
if (A == *root)
{
*root = B;
}
else if (A == ((A->parent)->left))
{
A->parent->left = B;
}
else
{
A->parent->right = B;
}
B->left = A;
A->parent = B;
}
void RightRotate(PNODE* root, PNODE A)
{
PNODE B = A->left;
if (B == LEAF)
{
return;
}
A->left = B->right;
if (B->right != LEAF)
{
(B->right)->parent = A;
}
B->parent = A->parent;
if (A == *root)
{
*root = B;
}
else if (A == ((A->parent)->left))
{
(A->parent)->left = B;
}
else
{
(A->parent)->right = B;
}
B->right = A;
A->parent = B;
}
/*
* 对给定的红黑树,找到存贮有特定key值的节点;
*/
PNODE FindNode(PNODE* root, ELEMENT key)
{
PNODE temp = *root;
PNODE track = *root;
while (temp)
{
track = temp;
if (key == temp->key)
{
break;
}
else if (key < (temp->key))
{
temp = temp->left;
}
else
{
temp = temp->right;
}
}
return track;
}
/*
* 找到比给定值 key 大的最少的节点
*/
PNODE FindNextNode(PNODE* root, ELEMENT key, PNODE start)
{
PNODE track = start;
if ( (track == LEAF) || (track->key != key) )
{
track = FindNode(root, key);
}
PNODE x = track;
if (track && track->right)
{
track = track->right;
while (track)
{
x = track;
track = track->left;
}
}
return x;
}
PNODE InsertNode(PNODE* root, ELEMENT key)
{
PNODE x, y;
PNODE z;
/*
* z: new node wanted to insert;
*/
z = (PNODE)malloc(sizeof(NODE));
if (z == NULL)
{
printf("can't alloc memory for new node /n");
return NULL;
}
x = *root;
/*
* y: keep track for the new node's parent;
*/
y = LEAF;
while (x != LEAF)
{
y = x;
if (key == (x->key))
{
printf("key has been confilct /n");
return NULL;
}
else if (key < (x->key))
{
x = x->left;
}
else
{
x = x->right;
}
}
z->parent = y;
if (y == LEAF)
{
*root = z;
}
else
{
if ( key < (y->key))
{
y->left = z;
}
else
{
y->right = z;
}
}
z->left = LEAF;
z->right = LEAF;
z->color = RED;
z->key = key;
return FixupTreeByInsert(root, z);
}
/*
增加节点,最开始,节点的颜色都设置为红色,有两种是简单的情况:
1) 插入的是根节点, 直接把节点颜色改成黑色即可;
2) 插入节点的父节点是黑色的,直接插入即可;
3) 父亲节点是红色的时候需要调整,此时祖父节点肯定存在(因为根节点颜色是黑色,所以父亲节点不可能是根节点)且颜色为黑色,否则跟父亲节点颜色冲突。
a. 父亲是红色,祖父是黑色,叔叔是红色,此时处理如下:
G(b) G(r)
/ / / /
/ / / /
P(r) U(r) P(b) U(b)
/ /
/ /
N(r) N(r)
这样,从左变到右, 冲突的节点从 N 转移到了 G, 这样从G从新调整红黑树;
b. 父亲是红色,祖父是黑色,叔叔是黑色
这里分两种情况,一是父亲节点是爷爷的左儿子,二是父亲节点是爷爷的右儿子,这么分是与这两种情况下调整策略是相对的。
仅以父亲节点是爷爷节点的左儿子来说明:
此时又分两种情况, 一是新加节点是父亲节点的左儿子,二是新加节点是父亲节点的右儿子。
b-1 : 是右儿子的调整如下:
G(b) G(b)
/ / / /
/ / / /
P(r) U(b) N(r) U(b)
/ /
/ /
N(r) P(r)
对P进行左旋后, 形成右边的局势,如果将 P视为原来的 N的话,现在变成了 b-2 这种情况;
b-2 : 是左儿子的调整如下:
G(b) P(b)
/ / / /
/ / / /
P(r) U(b) N(r) G(r)
/ /
/ /
N(r) U(b)
对G做右旋转之后,N节点的父亲变成黑色的,调整完成。
*/
PNODE FixupTreeByInsert(PNODE* root, PNODE z)
{
PNODE x = z;
while ( (x != (*root)) && ( Parent(x)->color == RED ))
{
if ( Uncle(x) && Uncle(x)->color == RED )
{
Parent(x)->color = BLACK;
Uncle(x)->color = BLACK;
Grand(x)->color = RED;
x = Grand(x);
}
else
{
if ( Parent(x) == Grand(x)->left )
{
if ( x == Parent(x)->right )
{
LeftRotate(root, Parent(x));
x = x->left;
}
Parent(x)->color = BLACK;
Grand(x)->color = RED;
RightRotate(root, Grand(x));
}
else
{
if (x == Parent(x)->left )
{
RightRotate(root, Parent(x));
x = x->right;
}
Parent(x)->color = BLACK;
Grand(x)->color = RED;
LeftRotate(root, Grand(x));
}
}
}
(*root)->color = BLACK;
return (*root);
}
PNODE DeleteNode(PNODE* root, ELEMENT key)
{
PNODE x;
/*
* 找到删去节点的位置
*/
x = FindNode(root, key);
if (x == LEAF)
{
return LEAF;
}
PNODE y;
/*
* 找到整个序列中在删除节点后面的节点,用它替换要删的节点,然后把这个节点删去
*/
y = FindNextNode(root, key, x);
x->key = y->key;
/*
* will delete y;
*/
FixupTreeByDelete(root, y);
/*
* del black sun;
*/
if (y->left)
{
y->key = y->left->key;
free(y->left);
y->left = LEAF;
y->color = BLACK;
}
else if (y->right)
{
y->key = y->right->key;
free(y->right);
y->right = LEAF;
y->color = BLACK;
}
else
{
if (y != *root)
{
if (y == Parent(y)->left)
{
Parent(y)->left = LEAF;
}
else
{
Parent(y)->right = LEAF;
}
}
else
{
*root = LEAF;
}
free(y);
}
return x;
}
/*
删去节点的调整操作如下:
首先,有两种简单情况。
1) 要删去的节点颜色是红色的,这样它的父亲和儿子都是黑色的,让它的儿子直接代替它就可以了;
2) 要删去的节点颜色是黑色的,但是它有一个红色的儿子,这样将儿子颜色编程黑色,直接代替它就可以了;
剩下的情况是要进行调整的:
删去的节点颜色是黑色的,它的儿子颜色都是黑色的。(如果儿子为null, 那么视为颜色是黑色的)
以下的操作分两种情况,一是删去的节点是父亲的左儿子,二是删去的节点是父亲的右儿子,这两种情况下做的操作是相对的,下面以是左儿子这种情况说明.
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
a): 兄弟节点是红色的,这样,父亲颜色是黑色,兄弟节点的儿子节点颜色是黑的;
P(b) S(b)
/ / / /
/ / / /
N(b) S(r) P(r) Sr(b)
/ / / /
/ / / /
Sl(b) Sr(b) N(b) Sl(b)
对P作左旋操作,完成之后, N节点的兄弟颜色变成了黑色,转化成下面的情况之一;
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
b): 兄弟节点是黑色的。
/* 以 Sl 称呼兄弟节点的左儿子, Sr 称呼兄弟节点的右儿子 */
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
b-1): Sl = b, Sr = b;
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
b-1-1) 父亲节点是黑色的;
P(b) P(b)
/ / / /
/ / / /
N(b) S(b) N(b) S(r)
/ / / /
/ / / /
Sl(b) Sr(b) Sl(b) Sr(b)
将 S 的颜色变成红色的,这样在删去 N 后, 通过 P 的路径上的黑色节点会少一个,变成了以 P为基点再作一轮调整,注意,这里分类是以兄弟节点的颜色来区分的,是因为不管怎么调整,兄弟节点原来都是具有红黑树的性质,可以作出当兄弟节点是红色的,父亲节点和兄弟节点儿子颜色是黑色这样的判断。
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
b-1-2) 父亲节点是红色的;
P(r) P(b)
/ / / /
/ / / /
N(b) S(b) N(b) S(r)
/ / / /
/ / / /
Sl(b) Sr(b) Sl(b) Sr(b)
通过以上的调整, P-N 这条路径多一个黑色的节点,把N删去之后刚好,调整结束;
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
b-2): Sl = r, Sr = b;
S(b) Sl(b)
/ / / /
/ / / /
Sl(r) Sr(b) # S(r)
/ /
/ /
# Sr(b)
对S节点右旋之后, #肯定是黑色的, 这样N的新的兄弟节点就是原来的 Sl 节点,这样变成了兄弟节点的左儿子是黑色的,右儿子是红色的,变成了情况 b-3);
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
b-3): Sl = (r/b) Sr = r;
P(r/b) S(r/b)
/ / / /
/ / / /
N(b) S(b) P(b) Sr(b)
/ /
/ /
Sr(r) N(b)
将 P 作一个左旋, S 颜色和P颜色交换, Sr 颜色变成红色, 可以验证删去 N 后,刚好保持了红黑树的性质,所以调整到此结束
*/
void FixupTreeByDelete(PNODE* root, PNODE z)
{
PNODE del = z;
if ( (del->color == RED) ||
(del->left && del->left->color == RED) ||
(del->right && del->right->color == RED) )
{
return;
}
while (z != (*root) )
{
if ( Brother(z) == LEAF)
{
z = Parent(z);
}
else if ( (Brother(z)->color == BLACK) &&
(Parent(z)->color == BLACK) &&
(GetColor(Brother(z)->left) == BLACK) &&
(GetColor(Brother(z)->right) == BLACK) )
{
Brother(z)->color = RED;
z = Parent(z);
}
else
{
if (z == Parent(z)->left)
{
if (Brother(z)->color == RED)
{
/*
* 将父亲的颜色变成黑色;
*/
Parent(z)->color = RED;
Brother(z)->color = BLACK;
LeftRotate(root, Parent(z));
}
else if ( Parent(z)->color == RED &&
GetColor(Brother(z)->left) == BLACK &&
GetColor(Brother(z)->right) == BLACK )
{
Parent(z)->color = BLACK;
Brother(z)->color = RED;
break;
}
else if ( GetColor(Brother(z)->left) == RED &&
GetColor(Brother(z)->right) == BLACK)
{
Brother(z)->color = RED;
Brother(z)->left->color = BLACK;
RightRotate(root, Brother(z));
}
else if ( GetColor(Brother(z)->right) == RED)
{
Brother(z)->color = Parent(z)->color;
Parent(z)->color = BLACK;
Brother(z)->right->color = BLACK;
LeftRotate(root, Parent(z));
break;
}
else
{
printf("bad case comes here ......../n");
}
}
else
{
if (Brother(z)->color == RED)
{
Brother(z)->color = BLACK;
Parent(z)->color = RED;
RightRotate(root, Parent(z));
}
else if ( (Parent(z)->color == RED) &&
(GetColor(Brother(z)->left) == BLACK) &&
(GetColor(Brother(z)->right) == BLACK) )
{
Parent(z)->color = BLACK;
Brother(z)->color = RED;
break;
}
else if ( GetColor(Brother(z)->left) == BLACK &&
GetColor(Brother(z)->right) == RED )
{
Brother(z)->color = RED;
Brother(z)->right->color = BLACK;
LeftRotate(root, Brother(z));
}
else if ( GetColor(Brother(z)->left) == RED)
{
Brother(z)->color = Parent(z)->color;
Parent(z)->color = BLACK;
Brother(z)->left->color = BLACK;
RightRotate(root, Parent(z));
break;
}
else
{
printf("bad case ... /n");
}
}
}
}
}
PSQ SQ_Init(void)
{
PSQ q = (PSQ)malloc(sizeof(SQ));
if (q != NULL)
{
memset(q, 0, sizeof(SQ));
q->index = 0;
q->size = 2047;
}
return q;
}
void SQ_Destory(PSQ q)
{
if (q)
{
free(q);
}
}
int SQ_Push(PSQ q, PNODE n)
{
if (q->index >= q->size )
{
printf("stack over flow .. /n");
return 0;
}
q->index++;
q->data[q->index] = n;
}
int SQ_IsEmpty(PSQ q)
{
if (q->index <= 0)
{
return 1;
}
return 0;
}
PNODE SQ_Pop(PSQ q)
{
if ( SQ_IsEmpty(q))
{
printf("no other element in stack .... /n");
return LEAF;
}
PNODE ret = q->data[q->index];
q->index--;
return ret;
}
PNODE SQ_Top(PSQ q)
{
return q->data[q->index];
}
void VisitNode(PNODE n)
{
printf("[key = %d] /n", n->key);
}
void TravelTheTree(PNODE* root)
{
PNODE p = (*root);
PSQ sq = NULL;
sq = SQ_Init();
while (p || (!SQ_IsEmpty(sq)))
{
while (p)
{
SQ_Push(sq, p);
p = p->left;
}
p = SQ_Pop(sq);
VisitNode(p);
p = p->right;
}
SQ_Destory(sq);
}
int _tmain(int argc, _TCHAR* argv[])
{
int Data[] = {4, 8 ,2, 1, 3 ,5, 29, 12, 17, 33 };
int Data_Del[] = {1,2,3,4,5,8,12,17,29,33};
for (int i = 0; i < sizeof(Data)/sizeof(int); i++)
{
InsertNode(&root, Data[i]);
}
printf("after insert element: /n");
TravelTheTree(&root);
for (int i = 0; i < sizeof(Data)/sizeof(int); i++)
{
DeleteNode(&root, Data[i]);
printf("delete key = %d /n", Data[i]);
printf("===================================== /n");
TravelTheTree(&root);
}
return 0;
}
相关参考见: http://zh.wikipedia.org/wiki/%E7%BA%A2%E9%BB%91%E6%A0%91