下面網址中是紅黑樹很好的教材,很詳細。node
http://blog.csdn.net/eric491179912/article/details/6179908算法
另外經典教材就是算法導論中關於紅黑樹的章節了,以算法導論爲主,實在不明白的地方再去網上查找資料。測試
紅黑樹是一種特殊的二叉查找樹,你們都知道二叉查找樹的複雜度最壞狀況爲O(h),爲了減低最壞狀況的複雜度,大神們設計了許多種二叉查找樹的改進版本,紅黑樹即是其中之一,它能夠保證在最壞狀況下複雜度爲O(lgn),也就是說h < lgn。spa
紅黑樹的五個性質.net
1)每一個節點或者是紅色,或者是黑色設計
2)根節點是黑色3d
3)每一個葉子節點是黑色的(此處的葉子節點指的是外部節點)指針
4)紅色節點的兩個孩子都是黑色的blog
5)對於每一個節點,從該節點到其子孫葉子節點的全部路徑上包含相同數目的黑色節點get
紅黑樹節點的定義
typedef struct node { int color; int key; struct node *p;//指向父節點 struct node *left, *right; }RBtreeNode;
與二叉搜索樹相比較,多出了2部分,本節點的顏色屬性和指向父節點是指針,之因此須要指向父節點是爲了後序操做的便利。
紅黑樹的左旋和右旋
在節點x上左旋,是以x和x的右孩子y之間的軸爲支點,旋轉結束後x成爲y的左孩子;在節點y上右旋,是以y和y的左孩子x之間的軸爲支點,旋轉結束後y是x的右孩子;如圖所示
,理論上與二叉搜索樹的旋轉沒有任何區別
紅黑樹的插入
假設新插入節點z,咱們將其置爲紅色,可能破壞性質2)和性質4),違反性質2)是由於新插入的點成爲了根節點,違反性質4)是由於z->p也是紅色;插入z後,從底向上逐層調整樹的結構和顏色,使其仍然知足紅黑樹的性質。既然從底層開始調整,咱們能夠只考慮違反性質4),固然在調整過程當中毫不容許出現違反其餘性質的現象。
前提z的父親是紅色
case1--z的叔叔是紅色
z的叔叔uncle_z是紅色,那z的爺爺確定是黑色,能夠把z的父親和叔叔置爲黑色,z的爺爺置爲紅色,z <- z的爺爺,而後繼續向上操做。
case2--uncle_z是黑色,且z和uncle_z不是同一方向的孩子,即z是左孩子,uncle_z是右孩子;或者z是右孩子,uncle_z是左孩子
case2.1--z是左孩子,uncle_z是右孩子,以下面左圖所示。咱們以z的爺爺爲輸入,作一次右旋操做,同時把parent_z置爲黑色,gparent_z置爲紅色,整棵樹調整結束。
左右分割
case2.2--z是右孩子,uncle_z是左孩子,如上面右圖所示。咱們,以z的爺爺爲輸入,作一次左旋操做,同時把parent_z置爲黑色,gparent_z置爲紅色,整棵樹調整結束。
能夠看到,case2.1和case2.2是對稱的兩種狀況。
case3--uncle_z是黑色,且z和uncle_z是同一方向的孩子,即z是左孩子,uncle_z也是左孩子;或者z是右孩子,uncle_z也是右孩子
case3.1--z和uncle_z同時是左孩子,以下面左圖所示。咱們以z的父親爲輸入,作一次右旋操做,同時把z置爲旋轉前z的父親,變成了case2.2,有木有!!
左右分割
case3.2--z和uncle_z同時是右孩子,如上面右圖所示。咱們以z的父親爲輸入,作一次左旋操做,同時把z置爲旋轉前z的父親,變成了case2.1。
插入的最後,在把root的顏色置爲黑色,完事。
紅黑樹的刪除
假設被刪除節點是z,能夠找到真正要被刪除的節點y,即若是z至多有一個孩子,y等於z;不然y是z的中序後繼,此時y至多有一個右孩子;總的說來y至多隻有一個右孩子x。若是y是紅色,刪除y後仍然可以保證紅黑樹的5個性質;若是y是黑色,可能違反性質2),4),5)。刪除y時就是把x代替了y的位置,咱們能夠給x額外增長一個黑色,使其成爲了雙黑色和紅黑色,這樣知足了性質5),但違反性質1)。
若是x是紅黑色,咱們將其置爲黑色,調整結束;
若是x是根節點,咱們將其置爲黑色,結束;
若是x是雙黑色,作必要的旋轉和塗色。
假設parent_x爲刪除節點y後x的父節點,實際上就是y的父節點,那麼parent_x必定是有兩個孩子的,由於此時y非空,且y是黑色,在不違反性質5)的前提下,y必定有兄弟。令parent_x的另外一個孩子爲w,即x的兄弟爲w
case1--w爲黑色,且w的兩個孩子都是黑色
由於w是黑色,x是雙重黑色,能夠同時去掉x和w的黑色,x的父節點增長一重黑色,不會違反性質5),而後把x賦值給x的父節點,繼續循環。以下面兩幅圖所示
左右分割
case2--w是黑色,且w同一方向的孩子是紅色,即若w是左孩子,w的左孩子是紅色;若w是右孩子,w的右孩子是紅色。咱們能夠經過旋轉使x的高度減一,而且在x和x的父親之間增長一個黑色節點,最後把x置爲根節點,循環結束
case2.1--w是黑色,w是左孩子,w的左孩子是紅色,以w的父節點爲輸入,作一次左旋,而且作一些顏色塗改
左右分割
case2.2--w是黑色,w是右孩子,w的右孩子是紅色,以w的父節點爲輸入,作一次右旋,而且作一些顏色塗改
case3--w是黑色,w同一方向的孩子是黑色,咱們能夠經過旋轉使其轉化爲case2
case3.1--w是黑色,w是左孩子,w的左孩子是黑色,那麼右孩子必定是紅色,不然就成了case1;以w爲輸入,作一次右旋,變成了case2.1
左右分割
case3.2--w是黑色,w是右孩子,w的右孩子是黑色,那麼左孩子必定是紅色,不然就成了case1;以w爲輸入,作一次左旋,變成了case2.2
case4--w是紅色的,則w確定有黑孩子,parent_x是黑色的,以parent_x爲輸入,作一次左旋,可轉變成case1,case2,或者case3
附源代碼,另附測試數據的大神博客網址:http://blog.csdn.net/v_JULY_v/article/details/6284050
//紅黑樹基本操做 #include <stdio.h> #include <list> #define BLACK 0 #define RED 1 typedef struct node { int color; int key; struct node *p; struct node *left, *right; }treeNode; //在節點x上左旋操做,以x和x右孩子之間的軸爲支點,旋轉結束後x成爲y的左孩子 // x y // / \ left_rotate / \ // lx y ---> x ry // / \ / \ // ly ry lx ly treeNode* left_rotate(treeNode* root, treeNode* x) { treeNode *y = x->right; x->right = y->left; if(y->left != NULL) (y->left)->p = x; y->p = x->p; if(x->p == NULL)//x是根節點 root = y; else if(x == (x->p)->left) (x->p)->left = y; else (x->p)->right = y; y->left = x; x->p = y; return root; } //在節點y上的右旋操做,以y和y的左孩子x之間的軸爲支點,旋轉結束後y是x的右孩子 // y x // / \ right_rotate / \ // x ry ---> lx y // / \ / \ // lx rx rx ry treeNode* right_rotate(treeNode* root, treeNode* y) { treeNode *x = y->left; y->left = x->right; if(x->right != NULL) (x->right)->p = y; x->p = y->p; if(y->p == NULL)//y是根節點 root = x; else if(y == (y->p)->left) (y->p)->left = x; else (y->p)->right = x; x->right = y; y->p = x; return root; } //插入新的節點後必須得調整 treeNode* rb_insert_fixup(treeNode *root, treeNode *z) { treeNode *uncle_z; while(z->p && z->p->color == RED && z->p->p) { if (z->p->p->left == z->p)//z的父親是左孩子 { uncle_z = z->p->p->right;//z的叔父是右孩子 //case1--叔父是右孩子,紅色 if(uncle_z && uncle_z->color == RED) { uncle_z->color = BLACK; z->p->color = BLACK; z->p->p->color = RED; z = z->p->p; } //case1 end else { //case2--叔父是右孩子,黑色 z是右孩子 if (z == z->p->right)//若是z是右孩子 { z = z->p; root = left_rotate(root, z); } //case2 end //case3--叔父是右孩子,黑色 z是左孩子 z->p->color = BLACK; z->p->p->color = RED; root = right_rotate(root, z->p->p); //case3 end } } else//z的父親是右孩子 { uncle_z = z->p->p->left;//z的叔父是左孩子 //case4--叔父是左孩子,紅色 if (uncle_z && uncle_z->color == RED) { uncle_z->color = BLACK; z->p->color = BLACK; z->p->p->color = RED; z = z->p->p; } //case4 end else { //case5--叔父是左孩子,黑色,z是左孩子 if (z == z->p->left) { z = z->p; root = right_rotate(root, z); } //case5 end //case6--叔父是左孩子,黑色 z是右孩子 z->p->color = BLACK; z->p->p->color = RED; root = left_rotate(root, z->p->p); //case6 end } } } root->color = BLACK; return root; } //插入新的節點 treeNode* rb_insert(treeNode *root, int value) { treeNode *z = new treeNode; z->key = value; treeNode *x = root; treeNode *y = NULL; while(x != NULL) { y = x; if(value == x->key) return root; if(value < x->key) x = x->left; else x = x->right; } z->p = y; if (y == NULL) { root = z; } else { if(value < y->key) y->left = z; else y->right = z; } z->left = NULL; z->right = NULL; z->color = RED; root = rb_insert_fixup(root, z); return root; } //刪除節點x的父節點後調整, x至關於多重黑色或者紅黑色 treeNode* rb_delete_fixup(treeNode *root, treeNode *x, treeNode *parent_x) { treeNode *w;//x_brother while(x!=root && (x == NULL ||x->color == BLACK)) { //x的父親parent_x必定有兩個孩子 if(x == parent_x->left) { w = parent_x->right;//x的右兄弟w //case1--x的兄弟w爲紅色,則w確定有黑孩子,左旋,轉換成case2,case3.... if(w->color == RED) { w->color = BLACK; parent_x->color = RED; root = left_rotate(root, parent_x); w = parent_x->right; //w從新置爲parent_x的右孩子 } //case1 end //case2--w爲黑色,w的兩個孩子(若是有)也是黑色 if((w->left == NULL || w->left->color == BLACK) && (w->right == NULL || w->right->color == BLACK)) { w->color = RED; x = parent_x; parent_x = parent_x->p; } //case2 end else { //case3--w的右孩子是黑色,左孩子是紅色 if(w->right == NULL || w->right->color == BLACK) { if(w->left != NULL)//若是w有左孩子,必定是紅色 w->left->color = BLACK; w->color = RED; root = right_rotate(root, w); w = parent_x->right; } //case3 end //case4 w的右孩子是紅色 if (w->right != NULL)//若是w有右孩子,必定是紅色 w->right->color = BLACK; w->color = parent_x->color; parent_x->color = BLACK; root = left_rotate(root, parent_x); x = root; } } else//與上面對稱 { w = parent_x->left;//x的左兄弟w //case5--x的兄弟w爲紅色,則w確定有黑孩子,右旋,轉換成case2,case3.... if(w->color == RED) { w->color = BLACK; parent_x->color = RED; root = right_rotate(root, parent_x); w = parent_x->left; } //case5 end //case6--w爲黑色,w的兩個孩子(若是有)也是黑色 if((w->left == NULL || w->left->color == BLACK) && (w->right == NULL || w->right->color == BLACK)) { w->color = RED; x = parent_x; parent_x = parent_x->p; } //case6 end else { //case7--w的左孩子是黑色,右孩子是紅色 if(w->left == NULL || w->left->color == BLACK) { if(w->right != NULL) w->right->color = BLACK; w->color = RED; root = left_rotate(root, w); w = parent_x->left; } //case7 end //case8 w的左孩子是紅色 if (w->left->color == RED) w->left->color = BLACK; w->color = parent_x->color; parent_x->color = BLACK; root = right_rotate(root, parent_x); x = root; //case8 end } } } if(x != NULL) x->color = BLACK; return root; } treeNode* rb_delete(treeNode *root, int value) { treeNode *z, *y, *x; z = root; while(z != NULL) { if(z->key == value) break; if(z->key < value) z = z->right; else z = z->left; } if(z == NULL) //木有找到要刪除的節點 return root; y = z; if(y->left!=NULL && y->right!=NULL)//兩個孩子的狀況,y是z的中序後繼 { y = y->right; while (y->left != NULL) { y = y->left; } z->key = y->key; } //x是y惟一的孩子或者NULL if(y->left != NULL) x = y->left; else x = y->right; if(x) x->p = y->p; if(y->p == NULL)//y是根節點 root = x; else if(y == y->p->left) y->p->left = x; else y->p->right = x; if(y->color==BLACK) root = rb_delete_fixup(root, x, y->p); delete y; return root; } treeNode* rb_find(treeNode *root, int value) { treeNode *x = root; int h = 0; while (x != NULL) { if (x->key == value) { if(x->color == RED) printf("RED "); else printf("BLACK "); printf("從0層計數,%d在第%d層\n", value, h); return x; } if (x->key < value) x = x->right; else x = x->left; h++; } return NULL; } void midOrder(treeNode *root) { if(root == NULL) return; midOrder(root->left); printf("%d-", root->key); if(root->color == RED) printf("RED "); else printf("BLACK "); midOrder(root->right); } void preOrder(treeNode *root) { if(root == NULL) return; printf("%d-", root->key); if(root->color == RED) printf("RED "); else printf("BLACK "); preOrder(root->left); preOrder(root->right); } int main() { int select, a; treeNode *root = NULL; do { printf("請輸入選擇 1--插入,2--查詢, 3--刪除, 4--輸出中序和前序,其餘跳出\n"); scanf("%d", &select); if (select == 1) { printf("輸入將要插入的值, -1表示結束\n"); while(scanf("%d", &a), a != -1) { root = rb_insert(root, a); } } else if (select == 2) { printf("輸入將要查詢的值, -1表示退出查詢\n"); while(scanf("%d", &a), a != -1) { if(rb_find(root, a) != NULL) { //printf("找到了\n"); } else printf("木有找到\n"); } } else if(select == 3) { printf("輸入將要刪除的值, -1表示退出刪除\n"); while(scanf("%d", &a), a != -1) { root = rb_delete(root, a); } } else if(select == 4) { printf("中序是:\n"); midOrder(root); printf("\n前序是:\n"); preOrder(root); printf("\n"); } else break; } while (true); getchar(); return 0; }
運行結果,據小雨本身測試沒有錯誤,歡迎你們前來拍磚