紅黑樹

紅黑樹node

         在瞭解紅黑樹以前,咱們必須先了解二叉搜索樹(又稱二叉排序樹,我在上一篇文章中有介紹),由於紅黑樹是一種特殊的二叉排序樹:在每一個節點上增長一個存儲位來表示節點的顏色,所以紅黑樹共有五個域:color,key,lchild,rchild,p。算法

         紅黑樹的提出:一個高度爲h的二叉排序樹能夠實現任何一種基本的動態集合操做:插入、刪除、查找等操做,可是當樹才高度比較高時,二叉樹就會退化成鏈表。而紅黑樹能確保在最壞的狀況下,基本的動態集合操做的時間爲O(logn).數組

紅黑樹的性質決定了紅黑樹的性能,紅黑樹共有五大性質函數

一、  每一個節點不是紅的,就是黑的。性能

二、  根節點是黑的。spa

三、  每一個葉節點都是黑的。指針

四、  若一個節點是紅的,則他的子節點都是黑的。code

五、  對於每一個節點,從該節點出發到其子孫葉節點的全部路徑上包含相同數目的黑節點。orm

圖片的信息比筆述更加清新明瞭,下圖就是一棵紅黑樹的幾種形式對象


 

上圖中,爲了便於處理邊界問題,咱們採用一個哨兵來表明NIL。哨兵NIL是一個與普通節點有相同域的對象。它的color域爲BLACK,其它域可隨意設置。我在程序中將p、lchild、rchild設置爲NULL,將key設置爲-1.將全部指向NIL的指針都指向哨兵NIL。

 

下面先說明兩個概念:內節點和外節點

內節點:把帶關鍵字的節點稱爲內節點。

外節點:把沒有子節點或父節點的節點稱爲外節點,咱們把外節點都當作是哨兵NIL。

因爲咱們關注的是關鍵字key,所以咱們主要關心內節點,因此在畫紅黑樹的時候,經常忽略葉子,如上圖c所示。

在介紹紅黑樹的插入和刪除前,咱們先必須介紹旋轉這個概念。由於它在紅黑樹的插入、刪除中,要用到不少。

旋轉:分爲左旋、右旋,它可以保持二叉排序樹性質局部操做。至於爲何可以保持性質,我也沒有深刻研究。前人不知道怎麼發現這個操做。

我始終認爲圖像更能直觀的表達更準確豐富的含義,我相信你們經過下圖便可以明白左旋和右旋了。

 

若是對上圖仍是不太明瞭,也不要緊,具體舉例能使你有更深入的認識,下圖是在x上左旋的過程:

 

下面附上左旋和右旋的代碼:

/*************************************************\
函數功能:左旋
輸入:    根節點、要左旋的節點、哨兵
輸出:    根節點
\*************************************************/
RBTree* Left_Rotate(RBTree* root,RBTree* x,RBTree* NIL)
{
	RBTree* y=NULL;
	y=x->rchild;
	x->rchild=y->lchild;
	
	if(y->lchild!=NIL)
		y->lchild->p=x;
	y->p=x->p;
	
	if(y->p==NIL)
	   root=y;
	else if(x==x->p->lchild)
		x->p->lchild=y;
	else
		x->p->rchild=y;
	y->lchild=x;
	x->p=y;
	return root;
}


/*************************************************\
函數功能:在節點z上右旋
輸入:    根節點、要右旋的節點、哨兵
輸出:    根節點
\*************************************************/
RBTree* Right_Rotate(RBTree* root,RBTree* x,RBTree* NIL)
{
	RBTree* y=NULL;
	y=x->lchild;
	x->lchild=y->rchild;
	if(y->rchild!=NIL)
		y->rchild->p=x;
	y->p=x->p;
	if(y->p==NIL)
	   root=y;
	else if(x==x->p->lchild)
		x->p->lchild=y;
	else
		x->p->rchild=y;
	y->rchild=x;
	x->p=y;
	return root;
}

 

插入操做:插入函數和插入修正函數

        在前一篇文章中我已經介紹了二叉排序樹,其中也有插入和刪除操做。由於紅黑樹也是二叉排序樹,所以其插入操做大同小異,不一樣之處在於,紅黑樹的性質會被插入和刪除操做所破壞,所以就須要修正。修正包括兩個操做從新着色、旋轉

從上面的分析可知,紅黑樹的插入操做分爲兩步,首先像二叉排序樹同樣進行插入操做,而後調用修正函數來保持紅黑樹的性質。在插入操做中,咱們都設置插入節點的color域爲紅而不是黑(若是是黑的話,性質4就不會破壞),爲何?請讀者好好思考。下面爲插入函數的實現:

 

/*************************************************\
函數功能:插入一個節點z
輸入:    根節點、插入的節點、哨兵
輸出:    根節點
\*************************************************/
RBTree* Insert(RBTree* root,RBTree* z,RBTree* NIL)
{
//	printf("ok ");
	RBTree* leaf=NIL;
	RBTree* p=root;//指向根節點
	while(p!=NIL)//根節點不爲空
	{
		//printf("dd");
		leaf=p;    //指向父節點
		if(z->key<p->key)
			p=p->lchild;
		else
			p=p->rchild;
	}

	z->p=leaf; //z爲y的孩子節點 y=leaf
	if(leaf==NIL) //根節點爲空
		root=z;
	else if(z->key<leaf->key)
		leaf->lchild=z;
	else
		leaf->rchild=z;
	
//	printf("%d ",root->key);
	

//	printf("%d ",root->color);
	return root;
}

 

        在Insert_FixUp插入修正函數中,循環截止條件爲 z->p是黑色。若是z->p是紅色,顯然這就違返了紅黑的樹性質4。在循環中,咱們要討論6種狀況,可是其中三種與另外三種是相互對稱的,它能夠由插入節點的父節點爲祖父節點的左孩子仍是右孩子來區分。下面我只討論插入節點的父節點爲祖父節點的左孩子的狀況。在每一次迭代中,咱們可能遇到如下三種狀況。

狀況一:叔叔是紅色的

 

        這時只要把插入節點z的父親z->p和uncle都設成黑色,並把祖父z->p->p設成紅色。這樣仍然確保了每一條路徑上的黑色節點數不變。而後把z指向z->p->p,並開始新一輪的迭代。以下圖:

 

狀況二:叔叔是黑色的狀況下,插入節點爲右孩子

         這時咱們只要把z指向z->p,而後作一次Left-Rotate(z)。就能夠把狀況轉化成狀況三。

 

狀況三:叔叔是黑色的狀況下,插入節點爲左孩子

        只要把 z->p設成黑色,把 z->p->p設成紅色,而後就調用     Right_Rotate(z->p->p),整棵樹就修正了。狀況二和狀況三以下圖:

 

插入修正函數的具體實現以下:

 

/*************************************************\
函數功能:插入修正來維持紅黑樹的性質
輸入:    根節點、插入的節點、哨兵
輸出:    根節點
\*************************************************/
RBTree* Insert_FixUp(RBTree* root,RBTree* z,RBTree* NIL)
{
	RBTree* y=z;
	while(y->p->color==RED)//循環截止條件爲父節點爲黑
	{
		
		if(y->p==y->p->p->lchild)//插入節點的父節點爲祖父節點的左孩子
		{
			RBTree* pr=y->p->p->rchild;
			if(pr->color==RED)//狀況一:叔叔是紅色的
			{
				y->p->color=BLACK;
				pr->color=BLACK;
				y->p->p->color=RED;
				y=y->p->p;
			}
			else //叔叔是黑色的,分兩種狀況
			{
				if(y==y->p->rchild)//狀況二:叔叔是黑色的狀況下,插入節點爲右孩子
				{
					y=y->p;
					root=Left_Rotate(root,y,NIL);//狀況二能夠經過左旋變成狀況三
				}
				y->p->color=BLACK;//狀況三:叔叔是黑色的狀況下,插入節點爲左孩子
				y->p->p->color=RED;
				root=Right_Rotate(root,y->p->p,NIL);
			}
		}
		
		else//插入節點的父節點爲祖父節點的左孩子,下面的狀況與上面相似
			{
			RBTree* pl=y->p->p->lchild;
			if(pl->color==RED)
			{
				y->p->color=BLACK;
				pl->color=BLACK;
				y->p->p->color=RED;
				y=y->p->p;
			}
			else 
			{
				if(y==y->p->lchild)
				{
					y=y->p;
					root=Left_Rotate(root,y,NIL);
				}
				y->p->color=BLACK;
				y->p->p->color=RED;
				root=Left_Rotate(root,y->p->p,NIL);
			}
		}

	}

	root->color=BLACK;
	return root;
}


刪除操做:刪除函數和刪除修正函數
          刪除操做和插入操做同樣,均可以和二叉排序樹同樣進行對比。紅黑樹的刪除操做分爲兩步,首先像二叉排序樹同樣進行刪除操做,而後調用修正函數來保持紅黑樹的性質。前一篇二叉排序樹的文章也講過,刪除操做要比插入操做複雜一些,紅黑樹也不例外。 刪除函數的具體實現以下

 

/*************************************************\
函數功能:刪除一個節點z
輸入:    根節點、要刪除的節點、哨兵
輸出:    根節點
\*************************************************/
 RBTree* Delete(RBTree* root,RBTree* node,RBTree* NIL) 
 {
        RBTree* toDel = node;
        if (node->lchild != NIL && node->rchild != NIL) 
		{
            toDel = TreeNext(node,NIL);
        }

        RBTree* temp = toDel;
        while (temp->p != NIL)
		{
            
            temp = temp->p;
        }

        RBTree* replace = (toDel->lchild != NIL)? toDel->lchild: toDel->rchild;
        replace->p = toDel->p;
        if (replace->p == NIL) 
		{
            root = replace;
        }
        else if (toDel == toDel->p->lchild) 
		{
            replace->p->lchild = replace;
        }
        else 
		{
            replace->p->rchild = replace;
        }
        if (toDel != node) 
		{
            node->key = toDel->key;
        }
        if (toDel->color == BLACK)
		{
            //修改樹,以保持平衡。
            root=Del_FixUp(root,replace,NIL);
        }
        delete toDel;
		return root;
    }


         在Del_FixUp刪除操做修正函數中,循環截止條件爲z->color== RED。若是z->p是黑色,即刪除的節點爲黑色,顯然這就違返了紅黑的樹性質5。在循環中,咱們要討論8種狀況,可是其中4種與另外4種是相互對稱的,它能夠由刪除的節點爲父節點的左孩子仍是右孩子來區分。下面我只討論刪除的節點爲父節點的左孩子的狀況:
在每一次迭代中,咱們可能遇到如下4種狀況:

狀況一:兄弟爲紅色

 

       這時咱們根據紅黑樹的性質能夠確定刪除的節點x->p是黑色、其兄弟節點w->lchild是黑色。咱們把x->pt與brother的顏色互換,而後作一次Left-Rotate(x->p)。作完以後x的新的兄弟:原w->lchild,是黑色的。所以咱們在不破壞紅黑樹性質的前提下,把狀況一轉換成了狀況2、狀況3、狀況四中的一個,以下圖(a):


 

狀況二:兄弟爲黑色,其兩個孩子爲黑色

       這時咱們只要把w設成紅色,而後把x移到x->p,這一次操做不會破壞紅黑樹的性質。以下圖(圖中節點B不必定是紅色,也多是黑色) 以下圖(b):

狀況三:兄弟爲黑色,且其左孩子爲紅色,右孩子爲黑色

       咱們把w與w->lchild的顏色互換,而後作Right-Rotate(w)。這樣作不會破壞紅黑樹的性質。這時x的新的兄弟就是原w->lchild。而狀況3被轉化成了狀況4, 如上圖(c):

狀況四:兄弟爲黑色,且其右孩子爲紅色

先把w與x->parent的顏色互換,再作Left-Rotate(x->parent)。這時圖中節點E(也就是原w->rchild)所在的路徑就確定少了一個黑色,而x所在的路徑則多了一個黑色。那麼咱們就把使E也爲黑色,這樣就保持了紅黑樹的性質。以下圖(d):

具體的代碼實現以下:

#include<stdio.h>
#include<malloc.h>

enum Color{RED,BLACK};

typedef struct node//紅黑樹的節點結構
{
	enum Color color;
	struct node *p,*lchild,*rchild;
	int key;
}RBTree;

RBTree* Insert(RBTree* root,RBTree* z,RBTree* NIL);//插入
RBTree* Insert_FixUp(RBTree* root,RBTree* z,RBTree* NIL);//插入修正
RBTree* Left_Rotate(RBTree* root,RBTree* x,RBTree* NIL);//左旋
RBTree* Right_Rotate(RBTree* root,RBTree* x,RBTree* NIL);//右旋
RBTree* Delete(RBTree* root,RBTree* node,RBTree* NIL);//刪除
void Layer(RBTree *p,int n);//廣度優先遍歷,用於查看紅黑樹的節點
RBTree* TreeNext(RBTree* node,RBTree* NIL);// 查找後繼
RBTree* TreePre(RBTree* node,RBTree* NIL);// 查找前趨
RBTree* TreeMax(RBTree* root,RBTree* NIL);// 查找最大值
RBTree* TreeMin(RBTree* root,RBTree* NIL);// 查找最小值
RBTree* Del_FixUp(RBTree* root,RBTree* delNode,RBTree* NIL);//刪除修正

void main()
{
	int arrayA[]={11,2,14,1,7,15,5,8,4};
	int n=sizeof(arrayA)/sizeof(int);
//	printf("%d\n",BLACK);

    RBTree* NIL=(RBTree*)malloc(sizeof(RBTree));//哨兵節點即外節點
	NIL->color=BLACK;
	NIL->key=-1;
	NIL->lchild=NIL->rchild=NULL;
	NIL->p=NULL;
	RBTree *root=NULL;//根節點
	root=NIL;
	for(int i=0;i<n;i++)
	{
		RBTree* z=(RBTree*)malloc(sizeof(RBTree));
		z->color=RED;
		z->key=arrayA[i];
		z->lchild=NIL;
		z->rchild=NIL;
		z->p=NIL;
		printf("\n插入節點的關鍵值爲%d ",z->key);	
		root=Insert(root,z,NIL);	
		printf("\n插入修正前的廣度遍歷:\n");
		Layer(root,n);
		root=Insert_FixUp(root,z,NIL);
	//	printf("%d\n",i);
		printf("插入修正後的廣度遍歷:\n");
		Layer(root,n);
		printf("\n");
		
	}
	printf("插入操做完成!!\n\n");
	printf("刪除節點的關鍵值爲%d\n ",root->lchild->rchild->key);
	printf("\n刪除頂節點後的廣度遍歷:\n");
	root=Delete(root,root->lchild->rchild,NIL);
	n=n-1;//刪除一個節點 n減一
	Layer(root,n);

	}


/*************************************************\
函數功能:插入一個節點z
輸入:    根節點、插入的節點、哨兵
輸出:    根節點
\*************************************************/
RBTree* Insert(RBTree* root,RBTree* z,RBTree* NIL)
{
//	printf("ok ");
	RBTree* leaf=NIL;
	RBTree* p=root;//指向根節點
	while(p!=NIL)//根節點不爲空
	{
		//printf("dd");
		leaf=p;    //指向父節點
		if(z->key<p->key)
			p=p->lchild;
		else
			p=p->rchild;
	}

	z->p=leaf; //z爲y的孩子節點 y=leaf
	if(leaf==NIL) //根節點爲空
		root=z;
	else if(z->key<leaf->key)
		leaf->lchild=z;
	else
		leaf->rchild=z;
	
//	printf("%d ",root->key);
	

//	printf("%d ",root->color);
	return root;
}

/*************************************************\
函數功能:插入修正來維持紅黑樹的性質
輸入:    根節點、插入的節點、哨兵
輸出:    根節點
\*************************************************/
RBTree* Insert_FixUp(RBTree* root,RBTree* z,RBTree* NIL)
{
	RBTree* y=z;
	while(y->p->color==RED)//循環截止條件爲父節點爲黑
	{
		
		if(y->p==y->p->p->lchild)//插入節點的父節點爲祖父節點的左孩子
		{
			RBTree* pr=y->p->p->rchild;
			if(pr->color==RED)//狀況一:叔叔是紅色的
			{
				y->p->color=BLACK;
				pr->color=BLACK;
				y->p->p->color=RED;
				y=y->p->p;
			}
			else //叔叔是黑色的,分兩種狀況
			{
				if(y==y->p->rchild)//狀況二:叔叔是黑色的狀況下,插入節點爲右孩子
				{
					y=y->p;
					root=Left_Rotate(root,y,NIL);//狀況二能夠經過左旋變成狀況三
				}
				y->p->color=BLACK;//狀況三:叔叔是黑色的狀況下,插入節點爲左孩子
				y->p->p->color=RED;
				root=Right_Rotate(root,y->p->p,NIL);
			}
		}
		
		else//插入節點的父節點爲祖父節點的左孩子,下面的狀況與上面相似
			{
			RBTree* pl=y->p->p->lchild;
			if(pl->color==RED)
			{
				y->p->color=BLACK;
				pl->color=BLACK;
				y->p->p->color=RED;
				y=y->p->p;
			}
			else 
			{
				if(y==y->p->lchild)
				{
					y=y->p;
					root=Left_Rotate(root,y,NIL);
				}
				y->p->color=BLACK;
				y->p->p->color=RED;
				root=Left_Rotate(root,y->p->p,NIL);
			}
		}

	}

	root->color=BLACK;
	return root;
}

/*************************************************\
函數功能:左旋
輸入:    根節點、要左旋的節點、哨兵
輸出:    根節點
\*************************************************/
RBTree* Left_Rotate(RBTree* root,RBTree* x,RBTree* NIL)
{
	RBTree* y=NULL;
	y=x->rchild;
	x->rchild=y->lchild;
	
	if(y->lchild!=NIL)
		y->lchild->p=x;
	y->p=x->p;
	
	if(y->p==NIL)
	   root=y;
	else if(x==x->p->lchild)
		x->p->lchild=y;
	else
		x->p->rchild=y;
	y->lchild=x;
	x->p=y;
	return root;
}


/*************************************************\
函數功能:在節點z上右旋
輸入:    根節點、要右旋的節點、哨兵
輸出:    根節點
\*************************************************/
RBTree* Right_Rotate(RBTree* root,RBTree* x,RBTree* NIL)
{
	RBTree* y=NULL;
	y=x->lchild;
	x->lchild=y->rchild;
	if(y->rchild!=NIL)
		y->rchild->p=x;
	y->p=x->p;
	if(y->p==NIL)
	   root=y;
	else if(x==x->p->lchild)
		x->p->lchild=y;
	else
		x->p->rchild=y;
	y->rchild=x;
	x->p=y;
	return root;
}


/*************************************************\
函數功能:刪除一個節點z
輸入:    根節點、要刪除的節點、哨兵
輸出:    根節點
\*************************************************/
 RBTree* Delete(RBTree* root,RBTree* node,RBTree* NIL) 
 {
        RBTree* toDel = node;
        if (node->lchild != NIL && node->rchild != NIL) 
		{
            toDel = TreeNext(node,NIL);
        }

        RBTree* temp = toDel;
        while (temp->p != NIL)
		{
            
            temp = temp->p;
        }

        RBTree* replace = (toDel->lchild != NIL)? toDel->lchild: toDel->rchild;
        replace->p = toDel->p;
        if (replace->p == NIL) 
		{
            root = replace;
        }
        else if (toDel == toDel->p->lchild) 
		{
            replace->p->lchild = replace;
        }
        else 
		{
            replace->p->rchild = replace;
        }
        if (toDel != node) 
		{
            node->key = toDel->key;
        }
        if (toDel->color == BLACK)
		{
            //修改樹,以保持平衡。
            root=Del_FixUp(root,replace,NIL);
        }
        delete toDel;
		return root;
    }


/*************************************************\
函數功能:刪除修正 維持紅黑樹的性質
輸入:    根節點、要刪除的節點、哨兵
輸出:    根節點
\*************************************************/
   RBTree* Del_FixUp(RBTree* root,RBTree* delNode,RBTree* NIL)
   {
        RBTree* p = delNode;
        while (p != root && p->color == BLACK)
		{
            if (p == p->p->lchild)//要刪除的節點爲父節點的左孩子
			{
                RBTree* brother = p->p->rchild;
                if (brother->color == RED) //狀況一:兄弟爲紅色
				{
                    brother->color = BLACK;
                    p->p->color = RED;
                    root=Left_Rotate(root,p->p,NIL);//通過旋轉後 兄弟變爲黑色,進入下面三種狀況之一
                    brother = p->p->rchild;
                }
                if (brother->lchild->color == BLACK&& brother->rchild->color == BLACK)//狀況二:兄弟爲黑色,其兩個孩子爲黑色
				{
                    brother->color = RED;
                    p = p->p;
                }
                else 
				{
                    if (brother->rchild->color == BLACK)//狀況三:兄弟爲黑色,且其左孩子爲紅色,右孩子爲黑色
					{
                        brother->lchild->color = BLACK;
                        brother->color = RED;
                        root=Right_Rotate(root,brother,NIL);//轉變爲狀況四
                        brother  = brother->p;
                    }
                    brother->color = brother->p->color;//狀況四:兄弟爲黑色,且其右孩子爲紅色
                    brother->p->color = BLACK;
                    brother->rchild->color = BLACK;
                    root=Left_Rotate(root,brother->p,NIL);
                    p = root;
                }
            }
            else//刪除的節點爲父節點的右孩子,下面的狀況與上面相似
			{
                RBTree* brother = p->p->lchild;
                if (brother->color == RED) 
				{
                    brother->color = BLACK;
                    p->p->color = RED;
                    root=Right_Rotate(root,p->p,NIL);
                    brother = p->p->lchild;
                }
                if (brother->lchild->color == BLACK&& brother->rchild->color == BLACK)
				{
                    brother->color = RED;
                    p = p->p;
                }
                else 
				{
                    if (brother->lchild->color == BLACK) 
					{
                        brother->rchild->color = BLACK;
                        brother->color = RED;
                        root=Left_Rotate(root,brother,NIL);
                        brother = brother->p;
                    }
                    brother->color = brother->p->color;
                    brother->p->color = BLACK;
                    brother->lchild->color = BLACK;
                    root=Right_Rotate(root,brother->p,NIL);
                    p = root;
                }
            }
        }
        p->color = BLACK;
		return root;
    }

   /*************************************************\
函數功能:廣度優先遍歷
輸入:    根節點、節點數
輸出:    無
\*************************************************/
void Layer(RBTree *p,int n)
{
	RBTree* queue[40];//queue數組用於存儲節點地址
	int count=0;
	RBTree* s;
	int rear=0;  //隊列尾指針
	int front=0; //隊列頭指針

	if(p!=NULL)//輸入的樹不爲空
	{
		rear=1; //初始化
		front=0;
		queue[rear]=p;
		while(front<rear)//判斷隊列是否爲空
		{
			front++;
			s=queue[front];
			if(s->key!=-1)
				count++;
			printf("key=%d color=%d\n",s->key,s->color);

			if(s->lchild!=NULL) //存儲左右子節點
			{
				rear++;
				queue[rear]=s->lchild;
			}
			if(s->rchild!=NULL)
			{
				rear++;
				queue[rear]=s->rchild;
			}
			
			if(count>=n)
				break;
		}
	}
}


/*************************************************\
函數功能:查找一個節點在中序遍列中的下一個節點(後繼)
輸入:    一個節點、哨兵
輸出:    該節點的後繼節點
\*************************************************/
 RBTree* TreeNext(RBTree* node,RBTree* NIL) 
 {
        RBTree* result;
        if (node->rchild!=NIL) 
		{
            result = TreeMin(node->rchild,NIL);
        }
        else 
		{
            result = node->p;
            RBTree* temp = node;
            while (result!=NIL&&temp==result->rchild) 
			{
                temp = result;
                result = result->p;
            }
        }
        return result;
  }

 
/*************************************************\
函數功能:一個節點在中序遍列中的前一個節點(前趨)
輸入:    一個節點、哨兵
輸出:    該節點的前趨節點
\*************************************************/
    RBTree* TreePre(RBTree* node,RBTree* NIL) 
	{
        RBTree* result;
        if (node->lchild !=NIL)
		{
            result = TreeMax(node->rchild,NIL);
        }
        else 
		{
            result = node->p;
            RBTree* temp = node;
            while (result != NIL && temp == result->lchild)
			{
                temp = result;
                result = result->p;
            }
        }
        return result;
    }

	    
/*************************************************\
函數功能:找到子樹中最大的節點
輸入:    根節點、哨兵
輸出:    子樹中最大的節點
\*************************************************/
    RBTree* TreeMax(RBTree* root,RBTree* NIL)
	{
        RBTree* result = root;
        while (result->rchild !=NIL) 
		{
            result = result->rchild;
        }
        return result;
    }

    
/*************************************************\
函數功能:找到子樹中最小的節點
輸入:    根節點、哨兵
輸出:    子樹中最小的節點
\*************************************************/
    RBTree* TreeMin(RBTree* root,RBTree* NIL)
	{
        RBTree* result = root;
        while (result->lchild !=NIL) 
		{
            result = result->lchild;
        }
        return result;
    }

最後給出運行結果的說明:在我電腦上的運行結果爲:

(key爲關鍵字,color=0表示爲紅色,color=1表示爲黑色,key=-1表明空節點)

插入節點的關鍵值爲11
插入修正前的廣度遍歷:
key=11 color=0
key=-1 color=1
key=-1 color=1
插入修正後的廣度遍歷:
key=11 color=1
key=-1 color=1
key=-1 color=1

插入節點的關鍵值爲2
插入修正前的廣度遍歷:
key=11 color=1
key=2 color=0
key=-1 color=1
key=-1 color=1
key=-1 color=1
插入修正後的廣度遍歷:
key=11 color=1
key=2 color=0
key=-1 color=1
key=-1 color=1
key=-1 color=1

插入節點的關鍵值爲14
插入修正前的廣度遍歷:
key=11 color=1
key=2 color=0
key=14 color=0
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1
插入修正後的廣度遍歷:
key=11 color=1
key=2 color=0
key=14 color=0
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1


插入節點的關鍵值爲1
插入修正前的廣度遍歷:
key=11 color=1
key=2 color=0
key=14 color=0
key=1 color=0
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1
插入修正後的廣度遍歷:
key=11 color=1
key=2 color=1
key=14 color=1
key=1 color=0
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1


插入節點的關鍵值爲7
插入修正前的廣度遍歷:
key=11 color=1
key=2 color=1
key=14 color=1
key=1 color=0
key=7 color=0
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1
插入修正後的廣度遍歷:
key=11 color=1
key=2 color=1
key=14 color=1
key=1 color=0
key=7 color=0
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1


插入節點的關鍵值爲15
插入修正前的廣度遍歷:
key=11 color=1
key=2 color=1
key=14 color=1
key=1 color=0
key=7 color=0
key=-1 color=1
key=15 color=0
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1
插入修正後的廣度遍歷:
key=11 color=1
key=2 color=1
key=14 color=1
key=1 color=0
key=7 color=0
key=-1 color=1
key=15 color=0
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1


插入節點的關鍵值爲5
插入修正前的廣度遍歷:
key=11 color=1
key=2 color=1
key=14 color=1
key=1 color=0
key=7 color=0
key=-1 color=1
key=15 color=0
key=-1 color=1
key=-1 color=1
key=5 color=0
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1
插入修正後的廣度遍歷:
key=11 color=1
key=2 color=0
key=14 color=1
key=1 color=1
key=7 color=1
key=-1 color=1
key=15 color=0
key=-1 color=1
key=-1 color=1
key=5 color=0
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1


插入節點的關鍵值爲8
插入修正前的廣度遍歷:
key=11 color=1
key=2 color=0
key=14 color=1
key=1 color=1
key=7 color=1
key=-1 color=1
key=15 color=0
key=-1 color=1
key=-1 color=1
key=5 color=0
key=8 color=0
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1
插入修正後的廣度遍歷:
key=11 color=1
key=2 color=0
key=14 color=1
key=1 color=1
key=7 color=1
key=-1 color=1
key=15 color=0
key=-1 color=1
key=-1 color=1
key=5 color=0
key=8 color=0
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1


插入節點的關鍵值爲4
插入修正前的廣度遍歷:
key=11 color=1
key=2 color=0
key=14 color=1
key=1 color=1
key=7 color=1
key=-1 color=1
key=15 color=0
key=-1 color=1
key=-1 color=1
key=5 color=0
key=8 color=0
key=-1 color=1
key=-1 color=1
key=4 color=0
插入修正後的廣度遍歷:
key=7 color=1
key=2 color=0
key=11 color=0
key=1 color=1
key=5 color=1
key=8 color=1
key=14 color=1
key=-1 color=1
key=-1 color=1
key=4 color=0
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=15 color=0


插入操做完成!!
造成的紅黑樹爲:



刪除節點的關鍵值爲5


刪除頂節點後的廣度遍歷:
key=7 color=1
key=2 color=0
key=11 color=0
key=1 color=1
key=4 color=1
key=8 color=1
key=14 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=-1 color=1
key=15 color=0
請按任意鍵繼續. . .

刪除節點5後的紅黑樹爲:


本文參考資料:《算法導論》

相關文章
相關標籤/搜索