C語(yǔ)言實(shí)現(xiàn)紅黑樹的實(shí)例代碼
因?yàn)榭磧?nèi)核的時(shí)候感覺(jué)紅黑樹挺有意思的,所以利用周末的時(shí)間來(lái)實(shí)現(xiàn)一下玩玩。紅黑樹的操作主要是插入和刪除,而刪除的時(shí)候需要考慮的情況更多一些。具體的操作就不在這里羅嗦了,百度文庫(kù)里面有一個(gè)比較有好的文章,已經(jīng)說(shuō)的很明白了。
在看具體的操作的時(shí)候有的人可能感覺(jué)有些情況是沒(méi)有考慮到的(如果沒(méi)有這種感覺(jué)的人很有可能根本沒(méi)有仔細(xì)地想)。但是那些“遺漏”的情況如果存在的話,操作之前的紅黑樹將違反那幾個(gè)規(guī)則。
寫代碼的時(shí)候很多次因?yàn)樯倏紤]情況而導(dǎo)致錯(cuò)誤,細(xì)節(jié)比較多,剛開始rb_node中沒(méi)有指向父節(jié)點(diǎn)的指針,寫的快吐血,然后還是加上了。代碼具體的含義可以結(jié)合文章和注釋來(lái)看(還是很好理解的)。下面的代碼中可能還有沒(méi)有考慮到的細(xì)節(jié),歡迎拍磚。
#include <stdio.h>
#include <stdlib.h>
const int RED = 0;
const int BLACK = 1;
struct rb_node{
rb_node* lchild, *rchild, *parent;
int key, colour;
};
rb_node* root;
rb_node* get_node(rb_node* parent, int key);
void rb_insert(int key);
rb_node* rb_search(int key);
void rb_delete(int key);
rb_node* clock_wise(rb_node* node);
rb_node* counter_clock_wise(rb_node* node);
void show_rb_tree(rb_node* node);
rb_node* get_node(rb_node* parent, int key){
rb_node *tmp = (rb_node*)malloc(sizeof(rb_node));
tmp->key = key;
tmp->colour = RED;
tmp->parent = parent;
tmp->lchild = tmp->rchild = NULL;
return tmp;
}
rb_node* clock_wise(rb_node* node){
if(node == NULL || node->lchild == NULL)
return NULL;
rb_node *rb_1=node, *rb_2=node->lchild, *rb_3=node->lchild->rchild;
if(rb_1->parent != NULL){
if(rb_1->parent->lchild == rb_1)
rb_1->parent->lchild = rb_2;
else
rb_1->parent->rchild = rb_2;
}else if(rb_1 == root){
root = rb_2;
}
rb_2->parent = rb_1->parent;
rb_1->parent = rb_2;
rb_2->rchild = rb_1;
rb_1->lchild = rb_3;
if(rb_3 != NULL)rb_3->parent = rb_1;
return rb_2;
}
rb_node* counter_clock_wise(rb_node* node){
if(node == NULL || node->rchild == NULL)
return NULL;
rb_node *rb_1=node, *rb_2=node->rchild, *rb_3=node->rchild->lchild;
if(rb_1->parent != NULL){
if(rb_1->parent->lchild == rb_1)
rb_1->parent->lchild = rb_2;
else
rb_1->parent->rchild = rb_2;
}
else if(rb_1 == root){
root = rb_2;
}
rb_2->parent = rb_1->parent;
rb_1->parent = rb_2;
rb_2->lchild = rb_1;
rb_1->rchild = rb_3;
if(rb_3 != NULL)rb_3->parent = rb_1;
return rb_2;
}
rb_node* rb_search(int key){
rb_node *p = root;
while(p != NULL){
if(key < p->key)
p = p->lchild;
else if(key > p->key)
p = p->rchild;
else
break;
}
return p;
}
void rb_insert(int key){
rb_node *p=root, *q=NULL;
if(root == NULL){
root = get_node(NULL, key);
root->colour = BLACK;
return;
}
while(p != NULL){
q = p;
if(key < p->key)
p = p->lchild;
else if(key > p->key)
p = p->rchild;
else return;
}
if(key < q->key)
q->lchild = get_node(q, key);
else
q->rchild = get_node(q, key);
while(q != NULL && q->colour == RED){
p = q->parent;//p won't null, or BUG.
if(p->lchild == q){
if(q->rchild != NULL && q->rchild->colour == RED)
counter_clock_wise(q);
q = clock_wise(p);
q->lchild->colour = BLACK;
}
else{
if(q->lchild != NULL && q->lchild->colour == RED)
clock_wise(q);
q = counter_clock_wise(p);
q->rchild->colour = BLACK;
}
q = q->parent;
}
root->colour = BLACK;
}
void show_rb_tree(rb_node* node){
if(node == NULL)
return;
printf("(%d,%d)\n", node->key, node->colour);
if(node->lchild != NULL){
printf("[-1]\n");
show_rb_tree(node->lchild);
}
if(node->rchild != NULL){
printf("[1]\n");
show_rb_tree(node->rchild);
}
printf("[0]\n");
}
void rb_delete(int key){
rb_node *v = rb_search(key), *u, *p, *c, *b;
int tmp;
if(v == NULL) return;
u = v;
if(v->lchild != NULL && v->rchild != NULL){
u = v->rchild;
while(u->lchild != NULL){
u = u->lchild;
}
tmp = u->key;
u->key = v->key;
v->key = tmp;
}
//u is the node to free.
if(u->lchild != NULL)
c = u->lchild;
else
c = u->rchild;
p = u->parent;
if(p != NULL){
//remove u from rb_tree.
if(p->lchild == u)
p->lchild = c;
else
p->rchild = c;
}
else{
//u is root.
root = c;
free((void*)u);
return;
}
//u is not root and u is RED, this will not unbalance.
if(u->colour == RED){
free((void*)u);
return;
}
free((void*)u);
u = c;
//u is the first node to balance.
while(u != root){
if(u != NULL && u->colour == RED){
//if u is RED, change it to BLACK can finsh.
u->colour = BLACK;
return;
}
if(u == p->lchild)
b = p->rchild;
else
b = p->lchild;
printf("%d\n", b->key);
//b is borther of u. b can't be null, or the rb_tree is must not balance.
if(b->colour == BLACK){
//If b's son is RED, rotate the node.
if(b->lchild != NULL && b->lchild->colour == RED){
if(u == p->lchild){
b = clock_wise(b);
b->colour = BLACK;
b->rchild->colour = RED;
p = counter_clock_wise(p);
p->colour = p->lchild->colour;
p->lchild->colour = BLACK;
p->rchild->colour = BLACK;
}
else{
p = clock_wise(p);
p->colour = p->rchild->colour;
p->rchild->colour = BLACK;
p->lchild->colour = BLACK;
}
return;
}
else if(b->rchild != NULL && b->rchild->colour == RED){
if(u == p->rchild){
b = counter_clock_wise(b);
b->colour = BLACK;
b->lchild->colour = RED;
p = clock_wise(p);
p->colour = p->rchild->colour;
p->rchild->colour = BLACK;
p->lchild->colour = BLACK;
}
else{
p = counter_clock_wise(p);
p->colour = p->lchild->colour;
p->lchild->colour = BLACK;
p->rchild->colour = BLACK;
}
return;
}
else{//if b's sons are BLACK, make b RED and move up u.
b->colour = RED;
u = p;
p = u->parent;
continue;
}
}
else{
if(u == p->lchild){
p = counter_clock_wise(p);
p->colour = BLACK;
p->lchild->colour = RED;
p = p->lchild;
}
else{
p = clock_wise(p);
p->colour = BLACK;
p->rchild->colour = RED;
p = p->rchild;
}
}
}
root->colour = BLACK;
}
int main(){
int i;
root = NULL;
for(i = 1; i <= 10; i++){
rb_insert(i);
}
rb_delete(9);
rb_delete(3);
rb_delete(7);
show_rb_tree(root);
printf("\n");
return 0;
}
上一篇:交換兩個(gè)文本內(nèi)容的C語(yǔ)言代碼
欄 目:C語(yǔ)言
本文標(biāo)題:C語(yǔ)言實(shí)現(xiàn)紅黑樹的實(shí)例代碼
本文地址:http://mengdiqiu.com.cn/a1/Cyuyan/3870.html
您可能感興趣的文章
- 04-02c語(yǔ)言函數(shù)調(diào)用后清空內(nèi)存 c語(yǔ)言調(diào)用函數(shù)刪除字符
- 04-02c語(yǔ)言的正則匹配函數(shù) c語(yǔ)言正則表達(dá)式函數(shù)庫(kù)
- 04-02func函數(shù)+在C語(yǔ)言 func函數(shù)在c語(yǔ)言中
- 04-02c語(yǔ)言中對(duì)數(shù)函數(shù)的表達(dá)式 c語(yǔ)言中對(duì)數(shù)怎么表達(dá)
- 04-02c語(yǔ)言用函數(shù)寫分段 用c語(yǔ)言表示分段函數(shù)
- 04-02c語(yǔ)言編寫函數(shù)冒泡排序 c語(yǔ)言冒泡排序法函數(shù)
- 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
- 04-02c語(yǔ)言分段函數(shù)怎么求 用c語(yǔ)言求分段函數(shù)
- 04-02C語(yǔ)言中怎么打出三角函數(shù) c語(yǔ)言中怎么打出三角函數(shù)的值
- 04-02c語(yǔ)言調(diào)用函數(shù)求fibo C語(yǔ)言調(diào)用函數(shù)求階乘


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 04-02c語(yǔ)言函數(shù)調(diào)用后清空內(nèi)存 c語(yǔ)言調(diào)用
- 04-02func函數(shù)+在C語(yǔ)言 func函數(shù)在c語(yǔ)言中
- 04-02c語(yǔ)言的正則匹配函數(shù) c語(yǔ)言正則表達(dá)
- 04-02c語(yǔ)言用函數(shù)寫分段 用c語(yǔ)言表示分段
- 04-02c語(yǔ)言中對(duì)數(shù)函數(shù)的表達(dá)式 c語(yǔ)言中對(duì)
- 04-02c語(yǔ)言編寫函數(shù)冒泡排序 c語(yǔ)言冒泡排
- 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
- 04-02c語(yǔ)言分段函數(shù)怎么求 用c語(yǔ)言求分段
- 04-02C語(yǔ)言中怎么打出三角函數(shù) c語(yǔ)言中怎
- 04-02c語(yǔ)言調(diào)用函數(shù)求fibo C語(yǔ)言調(diào)用函數(shù)求
隨機(jī)閱讀
- 04-02jquery與jsp,用jquery
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10C#中split用法實(shí)例總結(jié)
- 01-10delphi制作wav文件的方法
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改