連看帶寫花了三天,中途被指針引用搞得暈暈乎乎的。 插入和刪除的調整過程沒有看原理,只看了方法,直接照着寫的。算法
看了兩份資料,一份是算法導論第12-13章, 另外一份是網上的資料http://blog.csdn.net/v_JULY_v/article/details/6105630spa
下面C代碼是我根據 算法導論的僞碼寫的。.net
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef int DataType; typedef struct RBNode { RBNode *parent, *left, *right; //指向結點的父結點、左右孩子結點 DataType key; //結點數據 int color; //顏色 紅(r) 或 黑(b) }RBNode; //定義紅黑樹結點 RBNode Nil; RBNode * nil = &Nil; void left_rotate( RBNode * &T, RBNode * x) //左旋 x必定不能有引用 由於若是引用後 x與y->parent就是等價的了, y->parent改變 x就會改變 { RBNode * y; y = x->right; /************第一部分 y的左孩子 與 x間關聯*************/ x->right = y->left; //x認右孩子 if(y->left != nil) { y->left->parent = x; //孩子認parent } /************第一部分 y的左孩子 與 x間關聯 end*************/ /************第二部分 y 與 x的parent 關聯*************/ y->parent = x->parent; //y認 x的parent爲本身的parent //y的parent與x的地址是同樣的 int isroot = 0; if(x->parent == nil) //x的parent根據本身的狀況 認y爲左或右孩子 { isroot = 1; } else if(x == x->parent->left) { x->parent->left = y; } else { x->parent->right = y; } /************第二部分 y 與 x的parent 關聯 end*************/ /************第部分 x 與 y的關聯 *************/ y->left = x; //y認x爲孩子 x->parent = y; //x認y爲parent /************第部分 x 與 y的關聯 end*************/ if(isroot == 1) { T = y; } } void right_rotate(RBNode * &T, RBNode * x) //右旋 { RBNode * y; y = x->left; x->left = y->right; if(y->right != nil) { y->right->parent = x; } y->parent = x->parent; int isroot = 0; if(x->parent == nil) { isroot = 1; } else if(x == x->parent->right) { x->parent->right = y; } else { x->parent->left = y; } y->right = x; x->parent = y; if(isroot == 1) { T = y; } } void rb_insert_fixup(RBNode * &T, RBNode * z) //紅黑樹插入後的調整 注意z不能要引用 由於調整的過程當中z的值做爲位置標記會改變 但咱們不但願樹的結構由於z而變化 { RBNode * y; while(z->parent->color == 'r') { if(z->parent == z->parent->parent->left) //z的parent是左子的狀況 { //copy(z->parent->parent->right, y); y = z->parent->parent->right; if(y->color == 'r') //狀況1 z的parent和uncle都是紅色 把這兩個紅色染成黑色 把grandparent染成紅色 令z = grandparent 再次循環 { y->color = 'b'; z->parent->color = 'b'; z->parent->parent->color = 'r'; z = z->parent->parent; } else if(z == z->parent->right) //當前節點的父節點是紅色,叔叔節點是黑色,當前節點是其父節點的右子 對策:當前節點的父節點作爲新的當前節點,以新當前節點爲支點左旋。 { z = z->parent; left_rotate(T, z); } else //當前節點的父節點是紅色,叔叔節點是黑色,當前節點是其父節點的左子 解法:父節點變爲黑色,祖父節點變爲紅色,在祖父節點爲支點右旋 { z->parent->color = 'b'; z->parent->parent->color = 'r'; right_rotate(T, z->parent->parent); } } else //z的parent是右子的狀況 { y = z->parent->parent->left; if(y->color == 'r') { z->parent->color = 'b'; y->color = 'b'; z->parent->parent->color = 'r'; z = z->parent->parent; } else if(z == z->parent->left) { z = z->parent; right_rotate(T, z); } else { z->parent->color = 'b'; z->parent->parent->color = 'r'; left_rotate(T, z->parent->parent); } } } if(z->parent == nil) { z->color = 'b'; return; } else { return; } } void rb_insert(RBNode * &T, RBNode * z) //紅黑樹 插入工做 注意 z不要有引用 { RBNode * y = nil; RBNode * x = T; while(x != nil) //找到z適當的插入位置 { y = x; if(z->key < x->key) x = x->left; else x = x->right; } z->parent = y; if(y == nil) //parent 認孩子老是麻煩一些的 畢竟要區分是左是右 是否爲根 { T = z; } else if(z->key < y->key) { y->left = z; } else { y->right = z; } //對新插入的點處理, 染成紅色 z->left = nil; z->right = nil; z->color = 'r'; //調整紅黑樹 rb_insert_fixup(T, z); } RBNode * rb_findmax(RBNode * z) //找到以z爲樹根的樹的最大結點 { while(z->right != nil) { z = z->right; } return z; } RBNode * rb_findmin(RBNode * z) //找到以z爲樹根的樹的最小結點 { while(z->left != nil) { z = z->left; } return z; } RBNode * rb_successor(RBNode * z) //找z的後繼 { if(z->right != nil) { return rb_findmin(z->right); //若是z的right不爲空 後繼就是z的右子樹中最小的點 } else { RBNode * y = z->parent; while(y != nil && z == y->right) { z = y; y = y->parent; } return y; } } void rb_delete_fixup(RBNode * &T, RBNode * x) { RBNode* w; while(x != T && x->color == 'b') { if(x == x->parent->left) { w = x->parent->right; if(w->color == 'r') { w->color = 'b'; x->parent->color = 'r'; left_rotate(T, x->parent); w = x->parent->right; } if(w->left->color == 'b' && w->right->color == 'b') { w->color = 'r'; x = x->parent; } else { if(w->right->color == 'b') { w->left->color = 'b'; w->color = 'r'; right_rotate(T, w); w = x->parent->right; } w->color = x->parent->color; x->parent->color = 'b'; w->right->color = 'b'; left_rotate(T, x->parent); x = T; } } else { w = x->parent->left; if(w->color == 'r') { w->color = 'b'; x->parent->color = 'r'; right_rotate(T, x->parent); w = x->parent->left; } if(w->left->color == 'b' && w->right->color == 'b') { w->color = 'r'; x = x->parent; } else if(w->left->color == 'b') { if(w->left->color == 'b') { w->right->color = 'b'; w->color = 'r'; left_rotate(T, w); w = x->parent->left; } w->color = x->parent->color; x->parent->color = 'b'; w->left->color = 'b'; right_rotate(T, x->parent); x = T; } } } x->color = 'b'; } RBNode * rb_delete(RBNode * &T, RBNode * z) //紅黑樹 刪除節點 { //y 肯定刪除的結點是z仍是z的後繼 RBNode * y; y = (z->left == nil || z->right == nil) ? z : rb_successor(z); //x 是y的非nil子女 或是 nil RBNode * x; x = (y->left != nil) ? y->left : y->right; //無條件令x的parent = y的parent x->parent = y->parent; //刪除y 創建x與y的parent之間的聯繫 if(y->parent == nil) { T = x; } else if(y == y->parent->left) { y->parent->left = x; } else { y->parent->right = x; } //若是y!=z 將y的數據拷貝到z if(y != z) { //z的顏色不變 z->parent = y->parent; z->left = y->left; z->right = y->right; z->key = y->key; } if(y->color == 'b') { rb_delete_fixup(T, x); } return y; } int main() { nil->color = 'b'; //葉子結點都是黑的 nil->left = nil; nil->right = nil; nil->parent = nil; RBNode *T; T = nil; RBNode data[10]; for(int i = 0; i < 10; i++) { data[i].key = i + 1; RBNode * z = &data[i]; rb_insert(T, z); } RBNode * x = T->left->left; rb_delete(T, x); return 0; }