1. 程式人生 > >演算法之紅黑樹簡單理解和定義

演算法之紅黑樹簡單理解和定義

複製程式碼
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define MAXSIZE 1000
typedef int ElemType;
#define RED    0
#define BLACK    1
typedef struct RBTNode
{
    char    color;
    ElemType    data;
    struct RBTNode *    p;
    struct RBTNode *    left;
    struct RBTNode *    right;
}RBTNode, * PRBTNode;

typedef struct
RBTree { PRBTNode root; PRBTNode nil; //統一的空節點,該節點是黑的}RBTree, * PRBTree; int leftRotate (PRBTree tree, PRBTNode t); int rightRotate (PRBTree tree, PRBTNode t); PRBTNode insertRB (PRBTree tree, ElemType d); int insertRB_fixup (PRBTree tree, PRBTNode t); int createRBTree (PRBTree tree, ElemType d[], int
n); int initRB (PRBTree tree); PRBTNode maximum (PRBTree tree, PRBTNode t); PRBTNode minimum (PRBTree tree, PRBTNode t); PRBTNode next (PRBTree tree, PRBTNode t); PRBTNode precursor (PRBTree tree, PRBTNode t); int walkNext (PRBTree tree); int inOrderWalk (PRBTree tree, PRBTNode t); int deleteRB_fixup (PRBTree tree, PRBTNode c); PRBTNode deleteRB (PRBTree tree, PRBTNode t); int
main () { PRBTNode p; int d[MAXSIZE]; int n = 0; int i; RBTree tree; initRB(&tree); /* insertRB(&tree, 11); insertRB(&tree, 2); insertRB(&tree, 14); insertRB(&tree, 1); insertRB(&tree, 7); insertRB(&tree, 15); insertRB(&tree, 5); insertRB(&tree, 8); insertRB(&tree, 4); */ p= insertRB(&tree, 26); insertRB(&tree, 17); insertRB(&tree, 41); insertRB(&tree, 14); insertRB(&tree, 21); insertRB(&tree, 30); insertRB(&tree, 47); insertRB(&tree, 10); insertRB(&tree, 16); insertRB(&tree, 19); insertRB(&tree, 23); insertRB(&tree, 28); insertRB(&tree, 38); insertRB(&tree, 7); insertRB(&tree, 12); insertRB(&tree, 15); insertRB(&tree, 20); insertRB(&tree, 3); insertRB(&tree, 35); insertRB(&tree, 39); srand(time(NULL)); /* puts("請輸入資料的個數:"); scanf("%d",&n); printf("隨機生成的%d個數據是:\n",n); for (i = 0; i < n; i++) { d[i] = rand()%1000; printf("%d ",d[i]); } puts(""); puts("建樹開始"); createRBTree(&tree, d, n); */ inOrderWalk(&tree,tree.root); puts(""); printf("根是%d \n",tree.root->data); printf("刪除%d後:",p->data); deleteRB(&tree, p); inOrderWalk(&tree,tree.root); puts(""); printf("根是%d \n",tree.root->data); return 0; } PRBTNode insertRB (PRBTree tree, ElemType d) {//插入元素 //!!!記得插入的元素的初始化,p指向為父母節點,left和right賦值為NULL。 PRBTNode t = NULL; PRBTNode p = NULL; int flag = 0; //用來表示插入在左邊的樹還是右邊的樹 t = tree->root; //插入的節點是root,並做相應的初始化 if (tree->root == tree->nil) { tree->root = (PRBTNode)malloc(sizeof(RBTNode)); tree->root->data = d; tree->root->color = BLACK; tree->root->p = tree->root->left =tree->root->right = tree->nil; return tree->root; } while (t != tree->nil) { p = t; if (d < t->data) { flag = 0; t = t->left; } else { if (d > t->data) { flag = 1; t = t->right; } else { if ( (flag=rand()%2) == 0) t = t->left; else t = t->right; } } }//while //將t指向帶插入節點的地址,並初始化 t = (PRBTNode)malloc(sizeof(RBTNode)); t->data = d; t->color = RED; t->p = p; t->left = t->right = tree->nil; if (!flag) p->left = t; else p->right = t; insertRB_fixup(tree, t); return t; } int insertRB_fixup (PRBTree tree, PRBTNode t) {//插入的節點可能破壞紅黑樹的性質。該函式檢測插入的節點是否破壞了紅黑樹的性質。如果破壞了,就對樹進行調整,使其滿足紅黑樹的性質 while (t->p->color == RED) //只有插入節點的父親是紅色的才會破壞紅黑樹的性質(4.如果一個結點是紅的,那麼它的倆個兒子都是黑的) { if (t->p->p->left == t->p) //插入節點的父節點本身是left { if (t->p->p->right->color == RED) //case 1 { t = t->p->p; t->left->color = t->right->color = BLACK; t->color = RED; } else { if (t->p->right == t) //case 2 {//將case 2轉換為了case 3 t = t->p; //這步賦值是為了在轉換為case 3時,t指向的是下面的紅節點,和case 3的情況相一致 leftRotate(tree, t); } //case 3 t->p->color = BLACK; t->p->p->color = RED; rightRotate(tree, t->p->p); } }//if else //插入節點的父節點本身是right { if (t->p->p->left->color == RED) //case 1 { t = t->p->p; t->left->color = t->right->color = BLACK; t->color = RED; } else { if (t->p->left == t) //case 2 {//將case 2轉換為了case 3 t = t->p; //這步賦值是為了在轉換為case 3時,t指向的是下面的紅節點,和case 3的情況相一致 rightRotate(tree, t); } //case 3 t->p->color = BLACK; t->p->p->color = RED; leftRotate(tree, t->p->p); } }//else }//while tree->root->color = BLACK; return 0; } int leftRotate (PRBTree tree, PRBTNode t) { PRBTNode c; //左旋,c指向t的right c = t->right; if (t->right == tree->nil) //左旋,t的right不能為空 return 1; //這個if-else用於將t的父親節點的left或right點指向c,如果t的父節點為不存在,則樹的root指向c if (t->p != tree->nil) //判斷t是否為root { if (t->p->left == t) //判斷t是t的父節點的left還是right t->p->left = c; else t->p->right = c; } else tree->root = c; c->p = t->p; //更新c的父節點 t->right = c->left; if (c->left != tree->nil) c->left->p = t; c->left = t; t->p = c; return 0; } int rightRotate (PRBTree tree, PRBTNode t) { PRBTNode c; //右旋,c指向t的left c = t->left; if (t->left == tree->nil) //右旋,t的left不能為空 return 1; //這個if-else用於將t的父親節點的left或right點指向c,如果t的父節點為不存在,則樹的root指向c if (t->p != tree->nil) //判斷t是否為root { if (t->p->left == t) //判斷t是t的父節點的left還是right t->p->left = c; else t->p->right = c; } else tree->root = c; c->p = t->p; //更新c的父節點 t->left = c->right; if (c->right != tree->nil) c->right->p = t; c->right = t; t->p = c; return 0; } int createRBTree (PRBTree tree, ElemType d[], int n) {//用元素的插入建樹 int index = -1; int tmp = -1; srand(time(NULL)); while (n--) { index =(int) rand()%(n+1);//此時共有n+1個數據 tmp = d[index]; d[index] = d[n]; d[n] = tmp; insertRB(tree, d[n]); printf("插入%d\t",d[n]); } puts(""); return 0; }//createRBTree int initRB (PRBTree tree) {//紅黑樹的初始化 if (tree == NULL) return 0; tree->nil = (PRBTNode)malloc(sizeof(RBTNode)); tree->nil->color = BLACK; tree->root = tree->nil; return 0; }//initRB PRBTNode minimum (PRBTree tree, PRBTNode t) {//返回最小值,如果t是NULL返回NULL if (t == tree->nil) return NULL; while (t->left != tree->nil) t = t->left; return t; }//minimum PRBTNode maximum (PRBTree tree, PRBTNode t) {//返回最大值,如果t是NULL返回NULL if (t == tree->nil) return NULL; while (t->right != tree->nil) t = t->right; return t; }//maximum PRBTNode next (PRBTree tree, PRBTNode t) {//給出t的後繼的節點。如果沒有後繼,就返回NULL PRBTNode p; //指示父節點 if (t->right == tree->nil) { p = t->p; while (p != tree->nil && p->right == t) { t = p; p = t->p; } return p; //如果是最後一個元素,p的值為NULL } else return minimum(tree, t->right); }//next PRBTNode precursor (PRBTree tree, PRBTNode t) {//返回節點t前驅,如果沒有前驅,就返回NULL PRBTNode p; if (t->left == tree->nil) { p = t->p; while (p != tree->nil && p->left == t) { t = p; p = t->p; } return p; } else return maximum(tree, t->left); }//precusor int walkNext (PRBTree tree) {//遍歷二叉搜尋樹。先找到最小的元素,再通過用next()求後繼來遍歷樹 PRBTNode t; t = minimum(tree,tree->root); while (t != tree->nil) { printf("%d ",t->data); if (t->color == BLACK) printf("B\t"); else printf("R\t"); t = next(tree,t); } return 0; }//walkNext PRBTNode deleteRB (PRBTree tree, PRBTNode t) {//刪除資料。要求給處資料節點的指標 PRBTNode c = NULL; //c指向要取代被刪除節點的子節點 PRBTNode d = NULL; ElemType tmp; if (t == tree->nil) return NULL; //d指向真正要刪除的元素的下標。如果t的left和right都有值,則轉化為刪除t的後繼節點,並把後繼節點的內容複製給t指向的節點。 //而其他情況則直接刪除t指向的節點 if (t->left != tree->nil && t->right != tree->nil) { d = next(tree, t); //因為實際操作要刪除的是d指向的節點,所以先交換data tmp = d->data; d->data = t->data; t->data = tmp; } else d = t; //確定c的指向 if (d->left == tree->nil) c = d->right; else c = d->left; //將c的父親指標設為d的父親指標,c不會為空(因為存在nil節點) c->p = d->p; if (d->p != tree->nil) { if (d->p->left == d) d->p->left = c; else d->p->right = c; } else tree->root = c; if (d->color == BLACK) deleteRB_fixup(tree, c); return d; }//deleteRB int deleteRB_fixup (PRBTree tree, PRBTNode c) { PRBTNode b; //兄弟節點 while (c != tree->root && c->color == BLACK) { if (c == c->p->left) { b = c->p->right; if (b->color == RED) //case 1 {//b節點是紅的,可以說明c和b的父親節點是黑的。通過以下的操作可以吧case 1轉換為case 2,3,4中的一個 b->color = BLACK; c->p->color = RED; leftRotate(tree, c->p); b = c->p->right; //新的兄弟節點,這個節點一定是黑色的。這個節點之前是紅色節點的兒子 } if (b->right->color == BLACK && b->left->color == BLACK) //case 2 { b->color = RED; //將c的父節點的另一顆子樹黑節點減少1 c = c->p; //將c上移。上移之後,c的黑高度相同了(因為另一顆子樹的根節點有黑邊為紅) } else //case 3或case 4 { if (b->right->color == BLACK) //case 3 通過以下操作將case 3 轉化為case 4 { b->color = RED; b->left->color = BLACK; rightRotate(tree, b); b = c->p->right; } //case 4 //通過下面的操作,紅黑樹的性質恢復 b->color = b->p->color; b->p->color = BLACK; b->right->color = BLACK; leftRotate(tree, c->p); c = tree->root; //紅黑樹性質恢復,結束迴圈。不用break,是因為while結束後還要執行c->color = BLACK; } }//if (c == c->p->left) else { b = c->p->left; if (b->color == RED) //case 1 {//b節點是紅的,可以說明c和b的父親節點是黑的。通過以下的操作可以吧case 1轉換為case 2,3,4中的一個 b->color = BLACK; c->p->color = RED; rightRotate(tree, c->p); b = c->p->left; //新的兄弟節點,這個節點一定是黑色的。這個節點之前是紅色節點的兒子 } if (b->right->color == BLACK && b->left->color == BLACK) //case 2 { b->color = RED; //將c的父節點的另一顆子樹黑節點減少1 c = c->p; //將c上移。上移之後,c的黑高度相同了(因為另一顆子樹的根節點有黑邊為紅) } else //case 3或case 4 { if (b->left->color == BLACK) //case 3 通過以下操作將case 3 轉化為case 4 { b->color = RED; b->right->color = BLACK; leftRotate(tree, b); b = c->p->left; } //case 4 //通過下面的操作,紅黑樹的性質恢復 b->color = b->p->color; b->p->color = BLACK; b->left->color = BLACK; rightRotate(tree, c->p); c = tree->root; //紅黑樹性質恢復,結束迴圈。不用break,是因為while結束後還要執行c->color = BLACK; } }//else } c->color = BLACK; return 0; }//deleteRB_fixup int inOrderWalk (PRBTree tree, PRBTNode t) {//中序遍歷 if (t == tree->nil) return 0; putchar('('); inOrderWalk (tree, t->left); putchar(')'); printf(" %d ",t->data); if (t->color == BLACK) printf("B"); else printf("R"); putchar('('); inOrderWalk (tree, t->right); putchar(')'); return 0; }

相關推薦

演算法簡單理解定義

#include <stdio.h> #include <stdlib.h> #include <time.h> #define MAXSIZE 1000 typedef int ElemType; #define RED 0 #define BLACK

學習演算法導論——旋轉插入刪除

參考: 《演算法導論》 紅黑樹是一棵二叉搜尋樹,每個節點有一個標誌位表示顏色,該顏色可以是紅(RED)或黑(BLACK)。通過對任何一條從根到葉子的簡單路徑上各點的顏色進行約束,就能確保沒有一條路徑會比其他路徑長出2倍,因而是近似於平衡的。 紅黑樹每個節點有5個屬性,c

淺談演算法資料結構: 九 平衡查詢

前面一篇文章介紹了2-3查詢樹,可以看到,2-3查詢樹能保證在插入元素之後能保持樹的平衡狀態,最壞情況下即所有的子節點都是2-node,樹的高度為lgN,從而保證了最壞情況下的時間複雜度。但是2-3樹實現起來比較複雜,本文介紹一種簡單實現2-3樹的資料結構,即紅黑樹(

演算法導論 - 插入 C語言

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

【資料結構與演算法 --- 第十四篇

樹是一種非線性資料結構,這種資料結構要比線性資料結構複雜的多,因此分為三篇部落格進行講解: 第一篇:樹的基本概念及常用操作的Java實現(二叉樹為例) 第二篇:二叉查詢樹 第三篇:紅黑樹 第三篇:紅黑樹 開篇說明:對於紅黑樹的學習,近階段只需要掌握這種資料結構的思想、特點、適

演算法導論

作者:鄒祁峰 郵箱:[email protected] 日期:2013.12.27 16:45 轉載請註明來自"祁峰"的CSDN部落格 1 引言   博文《演算法導論 之 平衡二叉樹 - 列印》中使用遞迴演算法實現了平衡二叉樹的列印功能,仿照此博文中的程式碼可

演算法導論習題練習——的插入刪除

題目 13.3-2 將關鍵字 41、38、31、12、19、8 連續地插入一棵初始化為空的紅黑樹之後,試畫出該結果樹。 Solution: 13.4-3 在練習13.3-2中,我們將關鍵字41

演算法導論 - 刪除 C語言

                作者:鄒祁峰 郵箱:[email protected] 部落格

面試舊敵(直白介紹深入理解

開發十年,就只剩下這套架構體系了! >>>   

二叉的實現-插入刪除(三)

  #include <stdio.h>   #include <stdlib.h>

數據結構

紅黑樹;Java數據結構之紅黑樹 紅黑樹介紹:紅黑樹是一個平衡的二叉樹,但不是一個完美的平衡二叉樹。雖然我們希望一個所有查找都能在~lgN次比較內結束,但是這樣在動態插入中保持樹的完美平衡代價太高,所以,我們稍微放松逛一下限制,希望找到一個能在對數時間內完成查找的數據結構。這個時候,紅黑樹站了出來。 1:

數據結構Java版(八)

如何 當前 鏈接 根節點 java版 -- 查找 變色 繼承   紅黑樹是一種自動平衡的二叉查找樹,因為存在紅黑規則,所以有效的防止了二叉樹退化成了鏈表,且查找和刪除的速度都很快,時間復雜度為log(n)。   什麽是紅黑規則?   1.根節點必須是黑色的。   2.節點顏

篇3-平衡二叉查詢

一、概述         紅黑樹是一種自平衡樹在電腦科學中。二叉樹的每個節點都有一個額外的位,該位通常被解釋為節點的顏色(紅色或黑色)。這些顏色位用於確保樹在插入和刪除期間保持近似平衡。通過以滿足某些屬性的方式用兩種顏色之一繪製樹的每個節點來

資料結構個人筆記

   作者:Sky Wang    於 2013-08-08                              

知識全面詳解介紹及旋轉詳解

一、二叉查詢樹(二叉查詢樹、二叉搜尋樹 ) 二叉排序樹(Binary Sort Tree)或者是一棵空樹;或者是具有下列性質的二叉樹: 若左子樹不空,則左子樹上所有結點的值均小於它的根結點的值; 若右子樹不空,則右子樹上所有結點的值均大於它的根結點的值; 左

資料結構

紅黑樹簡介:   紅黑樹是一棵二叉搜尋樹,它在每個結點上增加了一個儲存位來表示結點的顏色,可以是RED 或 BLACK。通過對任何一條根到葉子的簡單路徑上各個結點的顏色進行約束,紅黑樹確保沒有一條路徑迴避其他路徑長處2倍,因而是近似平衡的。   樹的每個結點包含 5 個屬性:color,ke

的插入遍歷時間複雜度分析

       在平常的工作中,最常用的一種資料結構恐怕是std::map了。因此對其的時間複雜度分析是有必要的,編寫程式時做到心中有底。 一、理論分析        在stl中std::map和std::set都採用紅黑樹的方式實現。我們知道插入一個元素到紅黑樹的時間為log(N),其中N為當前紅黑樹的

演算法插入資料的情況與實現(三)

大家如果有玩魔方,我相信是可以理解我說的東西的,轉魔方就是先把第一面轉出來,然後把第一面作為底面,然後根據遇見的情況來轉魔方(是有公式的) 該系列到現在暫只有3篇文章:   【演算法】紅黑樹(二叉樹)概念與查詢(一):https://blog.csdn.net/lsr40/ar

演算法插入資料(變色,左旋、右旋)(二)

本人菜雞一隻,正在更新紅黑樹系列的文章。 該系列到現在暫只有3篇文章:   【演算法】紅黑樹(二叉樹)概念與查詢(一):https://blog.csdn.net/lsr40/article/details/85230703 【演算法】紅黑樹插入資料(變色,左旋、右旋)(二

演算法(二叉)概念與查詢(一)

誒,演算法這個東西,其實沒那麼簡單,但是也沒那麼難。 紅黑樹,其實已經有很多大佬都整理過了,而且文章部落格都寫得超好,我寫這篇文章的目的是:自己整理一次,這些知識才是自己的,否則永遠是別人的~   該系列到現在暫只有3篇文章: 【演算法】紅黑樹(二叉樹)概念與查詢(一):h