map,set的底層實現:紅黑樹[多圖,手機慎入]

 

      最近天下有一種頗不太平的感受,各地的亂刀砍人,處處是貪官服法。京東準備上市了,阿里最近也提交申請了,獵豹也逆襲了,聽說獵豹移動在國際市場上表現甚是搶眼。只有屌絲還在寫着代碼。花開花又謝,花謝花又開,爲何這麼多人沒有安全感呢?是轉型社會給你們帶來了浮躁,仍是什麼?不得而知!html

    另外,就上一篇文章的問題,還請你們各抒己見!一道面試題:C++相比C#或者java的優點到底在哪裏java

     OK,下面進入今天的主題。紅黑樹。面試

咱們時候用到了紅黑樹?安全

     C++STL中map,set的底層實現全是用的紅黑樹,java,C#等語言一樣如此。spa

爲何須要紅黑樹?code

      map,set底層都提供了排序功能,且查找速度快。紅黑樹其實是AVL的一種變形,可是其比AVL(平衡二叉搜索樹)具備更高的插入效率,固然查找效率會平衡二叉樹稍微低一點點,畢竟平衡二叉樹太完美了。可是這種查找效率的損失是很是值得的。它的操做有着良好的最壞狀況運行時間,而且在實踐中是高效的: 它能夠在O(log n)時間內作查找,插入和刪除,這裏的n是樹中元素的數目。htm

何爲紅黑樹?blog

      這裏二叉平衡樹的概念我就不提了。紅黑樹是每一個節點都帶有顏色屬性的二叉查找樹,顏色或紅色或黑色。排序

性質1 節點是紅色或黑色。
性質2 根節點是黑色。
性質3 每一個葉節點(NIL節點,空節點)是黑色的。
性質4 每一個紅色節點的兩個子節點都是黑色。(從每一個葉子到根的全部路徑上不能有兩個連續的紅色節點)
性質5 從任一節點到其每一個葉子的全部路徑都包含相同數目的黑色節點。
這些約束的好處是:保持了樹的相對平衡,同時又比AVL的插入刪除操做的複雜性要低許多。

操做:    get

     咱們知道平衡二叉樹要保持他的平衡性,旋轉是一項必不可少的工做。一樣,紅黑樹是一顆準平衡二叉樹,旋轉也是一項重要工做。旋轉有向左旋轉,向右旋轉,左右旋轉,右左旋轉。其實左右和右左旋轉就是左、右旋轉的二次使用,咱們這裏只談論向左旋轉、向右旋轉。

     樹的旋轉:

  

 

 

左右旋轉的就是上圖所示了,代碼以下:

 1 void leftRoate(rbTreeNode* x){//左旋轉
 2     rbTreeNode* y=x->right;  3     y->parent=x->parent;  4     if (x->parent==NULL)  5         root=y;  6     x->right=y->left;  7     if (y->left!=NULL)  8         y->left->parent=x;  9     if (x->parent!=NULL&&x->parent->left==x){ 10         x->parent->left=y; 11     }else if (x->parent!=NULL&&x->parent->right==x){ 12         x->parent->right=y; 13  } 14     y->left=x; 15     x->parent=y; 16 } 17 void rightRoate(rbTreeNode* x){//右旋轉
18     rbTreeNode* y=x->left; 19     x->left=y->right; 20     y->parent=x->parent; 21     if (x->parent==NULL) 22         root=y; 23     if (x->left!=NULL) 24         x->left->parent=x; 25     if (x->parent!=NULL&&x->parent->left==x){ 26         x->parent->left=y; 27     }else if (x->parent!=NULL&&x->parent->right==x){ 28         x->parent->right=y; 29  } 30     y->right=x; 31     x->parent=y; 32 }

 

     紅黑樹的插入:

     一直搜查到葉子節點X,X的父節點會出現如下幾種狀況:

    一、父節點是空,或者父節點的顏色是黑色。直接插入。

    二、父節點是紅色:

               1)父節點是爺爺結點的左結點

                   a,叔叔結點存在,且是紅色

                   b,叔叔結點不存在,或者是黑色

              2)父節點是爺爺結點的右孩子

                  c,叔叔結點存在且也爲紅色

                  d,叔叔結點不存在,或者爲黑色。

 

    第二種狀況:

 

 紅黑樹的插入操做就是上圖所示:代碼以下,

 1 void keepRBTreeBlance(rbTreeNode* x,rbTreeNode* y){  2     x->color=red;  3     while(x!=NULL&&x->parent!=NULL&&x->parent->color==red){//父節點是紅色
 4         if (x->parent==x->parent->parent->left){//父節點是爺爺結點的左節點
 5             rbTreeNode* z=x->parent->parent->right;//叔叔結點
 6             if(z&&x->parent->color==red){//叔叔結點存在,且也爲紅色。父和叔都置黑,爺爺置紅。
 7                 x->parent->color=black;//父置黑
 8                 z->color=black;//shushu置黑
 9                 x->parent->parent->color=red;//爺爺置紅
10                 x=x->parent->parent; 11             }else{//叔叔結點時黑色或者叔叔結點不存在的狀況。
12                 if (x==x->parent->right){//////........................問題
13                     //rbTreeNode* temp=x;
14                     x=x->parent; 15  leftRoate(x); 16  } 17                 x->parent->color=black; 18                 x->parent->parent->color=red; 19                 rightRoate(x->parent->parent); 20  } 21         }else if (x->parent==x->parent->parent->right){//父節點是爺爺結點的右節點
22             rbTreeNode* z=x->parent->parent->left;//叔叔結點
23             if (z&&z->color==red){//都是紅色
24                 x->parent->color=black;//父置黑
25                 z->color=black;//shushu置黑
26                 x->parent->parent->color=red;//爺爺置紅
27                 x=x->parent->parent; 28             }else{ 29                 if (x==x->parent->left){//若是是左孩子,須要一次右轉身跳投
30                     x=x->parent; 31  rightRoate(x); 32  } 33                 x->parent->color=black;//同時改變顏色。
34                 x->parent->parent->color=red; 35                 leftRoate(x->parent->parent); 36  } 37  } 38  } 39     root->color=black; 40 } 41 
42 bool insertRBTree(elemType elemValue){ 43     rbTreeNode* y=header; 44     rbTreeNode* x=root; 45     while(x!=NULL){ 46         y=x; 47         if (elemValue>x->data){//elemValue大於該節點的值,轉右子樹
48             x=x->right; 49         }else if (elemValue<x->data){//elemValue小於該節點的值,轉左子樹
50             x=x->left; 51         }else if (elemValue==x->data){//有相等的直接返回false
52             return false; 53  } 54  } 55     rbTreeNode* z=new rbTreeNode(); 56     z->data=elemValue; 57     if (y==header){//空直接插入
58         z->color=black; 59         root=z; 60         return true; 61     }else{ 62         if (y->data>elemValue) 63             y->left=z; 64         else
65             y->right=z; 66  } 67     z->parent=y; 68  keepRBTreeBlance(z,y); 69     return true; 70 }

 

     紅黑樹的刪除操做相似於B-樹的刪除,須要注意保持它的紅黑平衡性。紅黑的搜索那就和B-樹的查找如出一轍了,其實任何排序樹的操做都是同樣的。好比下面將要講到的B+樹。

    B樹系列還有一篇是B+樹,敬請期待。

    參考文獻:STL源碼剖析、百度。

 

    版權全部,歡迎轉載,可是轉載請註明出處:瀟一

相關文章
相關標籤/搜索