<span style="font-family: 'Microsoft YaHei'; background-color: rgb(255, 255, 255);">红黑树是一种二叉搜索树,具有良好的性质,树高至多2lg(n+1)。</span>
一棵红黑树是满足下列条件的二叉搜索树:
- 每个节点或是红色的或是黑色的。
- 根节点是黑色的。
- 叶子节点是黑色的。
- 如果一个节点是红色的,那么它的两个孩子是黑色的。
- 对每个节点,从该节点(不包括该节点)到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点。
本方案使用一个哨兵Nil来代表所有的NULL,根节点为T,根节点的父节点为Nil, 所有叶子节点为Nil。
红黑树的一个节点包含以下属性
typedef struct NODE
{
struct NODE *left; // 左孩子
struct NODE *right; // 右孩子
struct NODE *p; // 父节点
TREE_TYPE value; // 值
COLOUR colour; // 颜色
} Tree, Node;
1.假如定义一个函数
Node *Left(Node *x)
{
return x->left;
}
那么这样调用可以吗?(C89)
Left( node )->left = Nil;
答案是不可以。
而如果文件保存为.cpp的是可以的,C++支持这种写法。
我们可以嵌套Left( Left(node) )不可以作为左值(不显然的嘛)。
2.不得不说 C89里所有变量必须在语句块最前面定义,不然会报一堆错误,之前一直用的轻量级的Dev C++ 开发环境编译器GCC4.8.1,写着更爽一些,不过调试器太简单,VS的调试器很强大可以看清楚数据的结构,这对于理解程序的结构更有好处,虽然它的古老语法不太人性。什么你说我用VS写的时候随便啊for(int i= 0; i<n; ++i)都可以,只能说你写的真的不是C(VS2013没用过不清楚)。对C程序恐怕不太好移植。
用KEIL4写嵌入式程序时。 比如int config_lcd() ; 这样的声明会有一个警告,这更严格了。应该写为
int config_lcd(void) 就没警告啦!那int main() {} 、 void main(){}都不行啦。int main(void)才是标准,
3.有时用这样写
void counting_sort(char *source , char * des, int k )
{
char c[k];
..... ....
}
GCC是可以通过的,然而有些激进。
当然这些东西,很多书上会讲到,不过绝知此事要躬行,自己碰到这些问题才会理解更深刻。
下面是红黑树的代码
red_black_tree.h文件
#ifndef _RED_BLACK_TREE_H
#define _RED_BLACK_TREE_H
#define TREE_TYPE int // 树的类型
#define RED '0' // 红色
#define BLACK '1' // 黑色
#define COLOUR char
/* 红黑树节点 */
typedef struct NODE
{
struct NODE *left; // 左孩子
struct NODE *right; // 右孩子
struct NODE *p; // 父节点
TREE_TYPE value; // 值
COLOUR colour; // 颜色
} Tree, Node;
Node *get_node(Node* parent, int key);
/**
* x y
* / \ ==> / \
* a y left rotate x r
* / \ / \
* b r a b
*/
void left_rotate( Node *x );
/**
* right_rotate x y
* / \ <== / \
* a y right rotate x r
* / \ / \
* b r a b
*/
void right_rotate( Node *y );
/**
* 返回 x 的父节点
*/
Node *P(Node *x);
/**
* 返回 x 的左孩子
*/
Node *Left(Node *x);
/**
* 返回 x 的右孩子
*/
Node *Right(Node *x);
/**
* 在 T 中搜索值 value
* 返回指向该节点的指针
* 若不存在 返回 NULL
*/
Node *tree_seach(TREE_TYPE value);
/* 最小关键字元素 */
Node *tree_minimum(Node *x);
/**
* 修正插入节点 z 破坏的红黑树
*/
void rb_insert_fixup(Node *z);
/**
* 修正删除节点 z 破坏的红黑树
*/
void rb_delete_fixup(Node *x);
/**
* 向红黑树 T 插入值 value
*/
void rb_insert(TREE_TYPE value);
/**
* 向红黑树 T 删除值 value
*/
void rb_delete(TREE_TYPE value);
#endif
red_black_tree.c文件
/**
******************************************************************************
* @file red_black_tree.c
* @author summer
* @version V1.0
* @date 2015-06-30
* @brief C语言实现红黑树 (C89)
******************************************************************************
* @environment:
* IDE: Visual Studio 2010
*
******************************************************************************
*/
#include"red_black_tree.h"
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
Node *Nil = NULL; // 公共空节点 Nil(T)
extern Tree *T;
/* 配置一个节点 */
Node *get_node(Node* parent, TREE_TYPE value)
{
Node *tmp = (Node*)malloc(sizeof(Node));
assert(tmp != NULL);
tmp->value = value;
tmp->colour = RED;
tmp->p = parent;
tmp->left = tmp->right = Nil;
return tmp;
}
/**
* 左孩子
*/
Node *Left(Node *x)
{
return x->left;
}
/**
* 右孩子
*/
Node *Right(Node *x)
{
return x->right;
}
/**
* 父节点
*/
Node *P(Node *x)
{
return x->p;
}
/**
* left_rotate x y
* / \ ==> / \
* a y left rotate x r
* / \ / \
* b r a b
* 假设 根的父节点是 Nil
*/
void left_rotate( Node *x)
{
Node *y = x->right; // 看着图,很好理解
if(y == Nil)
{
printf("Right(x) is NULL !\n");
return;
}
x->right = y->left;
if(y->left != Nil)
{
y->left->p = x;
}
y->p = x->p;
if( P(x) == Nil ) // root(T) 根节点
{
T = y;
}
else if (x == x->p->left )
{
x->p->left = y;
}
else
{
x->p->right = y;
}
y->left = x;
x->p = y;
}
void right_rotate(Node *x)
{
Node *y = x->left; // 看着图,很好理解
if(y == Nil)
{
printf("Right(x) is NULL !\n");
return;
}
x->left = y->right;
if(y->right != Nil)
{
y->right->p = x;
}
y->p = x->p;
if( P(x) == Nil ) // root(T) 根节点
{
T = y;
}
else if (x == x->p->right )
{
x->p->right = y;
}
else
{
x->p->left = y;
}
y->right = x;
x->p = y;
}
/* 插入节点 O(lgn)*/
void rb_insert( TREE_TYPE value )
{
#if 1
Node *y = Nil;
Node *x = T;
Node *z = Nil;
if( T == NULL ) // 树是空的
{
T = get_node(Nil, value);
T->colour = BLACK;
return;
}
while(x != Nil)
{
y = x; // 保存 x
if( value < x->value)
{
x = x->left;
}
else if(value > x->value)
{
x = x->right;
}
else return;
}
z = get_node(y, value);
z->p = y;
if(y == Nil)
{
T = z;//get_node(y, value);
//return;
}
else if(value < y->value)
{
y->left = z;//get_node(y, value);
}
else
{
y->right = z;//get_node(y, value);
}
rb_insert_fixup(z);//修正插入节点 z 破坏的红黑树
#endif
}
void rb_insert_fixup(Node *z)
{
Node *y;
while(z->p->colour == RED) // z是红色,如果P(z)为红色,则违反规则4
{
if( z->p == z->p->p->left )
{
y = z->p->p->right; // y 为 z 的叔节点
if(y->colour == RED) // 如果z的叔节点为红色
{
z->p->colour = BLACK; // 把z的父节点涂黑
y->colour = BLACK; // 叔节点涂黑
z->p->p->colour = RED;// 父节点的父节点涂黑
z = z->p->p; // z指向父节点的父节点, 不看图是不容易理清的
}
else
{
if(z == z->p->right)
{
z = z->p;
left_rotate(z); // 执行一个左旋
}
z->p->colour = BLACK;
z->p->p->colour = RED;
right_rotate(z->p->p);
}
}//if
else // P(z) == Right( P( P(z) ) )
{
y = z->p->p->left; // y 为 z 的叔节点
if(y->colour == RED) // 如果z的叔节点为红色
{
z->p->colour = BLACK; // 把z的父节点涂黑
y->colour = BLACK; // 叔节点涂黑
z->p->p->colour = RED;// 父节点的父节点涂黑
z = z->p->p; // z指向父节点的父节点
}
else
{
if(z == z->p->left)
{
z = z->p;
right_rotate(z);
}
z->p->colour = BLACK;
z->p->p->colour = RED;
left_rotate(z->p->p);
}
}//else
}//while
T->colour = BLACK;
}
/* v子树代替u子树, rb_delete 函数的辅助函数 */
void rb_transplant(Node *u, Node *v)
{
if(u->p == Nil)
{
T = v;
}
else if(u == u->p->left)
{
u->p->left = v;
}
else
{
u->p->right = v;
}
v->p = u->p;
}
/* 查找元素 O(lgn) */
Node *tree_seach(TREE_TYPE value)
{
Node *x = T;
while( x != Nil && x->value != value )
{
x = (value < x->value) ? x->left : x->right;
}
return x;
}
/* 最小关键字元素 */
Node *tree_minimum(Node *x)
{
while(x->left != Nil)
{
x = x->left;
}
return x;
}
void rb_delete_fixup( Node *x)
{
Node *w = NULL;
while(x != T && x->colour == BLACK )
{
if(x == x->p->left) // x 是左子树
{
w = x->p->right; // x 的兄弟
if(w->colour == RED) // x 的兄弟节点 w 是红色
{
w->colour = BLACK;
x->p->colour = RED;
left_rotate(x->p);
w = x->p->right;
}
if( (w->left->colour == BLACK) && (w->right->colour == BLACK) )
{// x 的兄弟节点 w 是黑色的, 且 w 的两个子节点都是黑色的
w->colour = RED;
x = x->p;
}
else
{
if( w->right->colour == BLACK)
{// x 的兄弟节点 w 是黑色的,且 w 的左孩子是红色的,w 的右孩子是黑色的
w->left->colour = BLACK;
w->colour = RED;
right_rotate(w);
w = x->p->right;
}
// x 的兄弟节点 w 是黑色的, 且 w 的右孩子是红色的
w->colour = x->p->colour;
x->p->colour = BLACK;
w->right->colour = BLACK;
left_rotate(x->p);
x = T;
}
}//if
else// x是右子树
{
w = x->p->left;// x 的兄弟
if(w->colour == RED) // x的兄弟节点是红色
{
w->colour = BLACK;
x->p->colour = RED;
right_rotate(x->p);
w = x->p->left;
}
if( (w->right->colour == BLACK) && (w->left->colour == BLACK) )
{
w->colour = RED;
x = x->p;
}
else
{
if( w->left->colour == BLACK )
{
w->right->colour = BLACK;
w->colour = RED;
right_rotate(w);
w = x->p->left;
}
w->colour = x->p->colour;
x->p->colour = BLACK;
w->left->colour = BLACK;
right_rotate(x->p);
x = T;
}
}//else
}//while
x->colour = BLACK;
}
/* 删除节点 O(lgn) */
void rb_delete(TREE_TYPE value)
{
Node *x = NULL;// x 指向 y 的唯一子节点或指向 Nil
Node *z = tree_seach( value); // O(lgn)
Node *y = z; // y 为从树中删除的节点或者移至树内的节点
COLOUR y_original_colour; // 保存 y 的颜色
if(z == Nil)
{
printf("Not found !\n");
return;
}
y_original_colour = y->colour;
if(z->left == Nil)
{
x = z->right;
rb_transplant(z, z->right);
}
else if(z->right == Nil)
{
x = z->left;
rb_transplant(z, z->left);
}
else// z 有两个节点
{
y = tree_minimum(z->right); // y指向z的后继
y_original_colour = y->colour;
x = y->right;
if(y->p == z)
{
x->p = y;
}
else
{
rb_transplant(y, y->right);
y->right = z->right;
y->right->p = y;
}
rb_transplant( z, y);
y->left = z->left;
y->left->p = y;
y->colour = z->colour;
}//else
if(y_original_colour == BLACK)
{
rb_delete_fixup(x);
}
free(z);
z = Nil;
//printf("delete success\n");
}
测试代码main.c
#include"red_black_tree.h"
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
extern Node *Nil; // T.NULL
Node *T; // T.root
int main(void)
{
int i;
Node *test_node;
/* config Nil */
Nil = (Node*)malloc( sizeof(Node) );
assert(Nil != NULL);
Nil->colour = BLACK; //nil的颜色设置为黑
/* config T.root */
T = NULL;
for(i = 1; i < 10; ++i)
{
rb_insert(i);
test_node = tree_seach(i);
if(test_node != Nil)
printf("%d\n", test_node->value);
else printf("Not found the value\n");
}
for(i = 1; i < 10; ++i)
{
rb_delete(i);
}
system("pause");
return 0;
}
调试状态下我们可以看到红黑树的结构
1~9插入一棵红黑树
4b
/ \
2r 6r
/ \ / \
1b 3b 5b 8b
/ \
7r 9r
符合红黑树的性质。
其他函数亦实现了功能。