二叉搜索樹—RBTree(紅黑樹)


       紅黑樹又稱二叉搜索樹,它主要是通過紅和黑兩種顏色(red、black)來標識節點。通過對任何一條從根節點到葉子節點路徑上的節點顏色進行約束,紅黑樹保證最長路徑不超過最短路徑的兩倍,所以說:紅黑樹是近似於平衡的



■下面是紅黑樹的主要特點:

        (1)紅黑樹的根節點是黑色的。

        (2)紅黑樹中若一個節點是紅色的,則它的兩個子節點必須是黑色的。

        (3)紅黑樹中從該節點到後代葉節點的路徑上,黑色節點數目是相同的。



       ◆紅黑樹的應用:

                 C++庫、linux內核、java庫等


       ◆紅黑樹與AVL樹的區別:

                  紅黑樹和AVL樹都是高效的平衡搜索樹,時間複雜度都是O(lgN);

                  紅黑樹對平衡的要求不是特別高,它只需要滿足最長路徑不超過最短路徑的兩倍,所以性能相對較高。



■下面是紅黑樹中節點結構:

enum color      //枚舉節點的兩種顏色
{
     RED,
     BLACK,
};

template <class K, class V>
struct RBTreeNode
{
     color _col;
     RBTreeNode<K, V>* _left;
     RBTreeNode<K, V>* _right;
     RBTreeNode<K, V>* _parent;
     K _key;
     V _value;
     
     RBTreeNode(const K& key, const V& value)
          :_key(key)
          , _value(value)
          , _left(NULL)
          , _right(NULL)
          , _parent(NULL)
          , _col(RED)          //顏色必須插入的是紅色,因爲要保證黑色節點的個數是平衡的
     { }
};



■下面分析紅黑樹的插入情況:

(1)


650) this.width=650;" width="659" height="324" title="無標題.png" style="width:659px;height:240px;" src="http://s2.51cto.com/wyfs02/M01/84/5D/wKiom1eOMAGhaLkaAACKpn9k5x4853.png" alt="wKiom1eOMAGhaLkaAACKpn9k5x4853.png" />




(2)


650) this.width=650;" width="661" height="323" title="無標題.png" style="width:660px;height:267px;" src="http://s4.51cto.com/wyfs02/M01/84/5D/wKioL1eOMFTx64CdAACh1WNItjI750.png" alt="wKioL1eOMFTx64CdAACh1WNItjI750.png" />


(3)


650) this.width=650;" width="661" height="322" title="無標題.png" style="width:660px;height:262px;" src="http://s2.51cto.com/wyfs02/M02/84/5D/wKioL1eOMSaD9UmLAACjGh-zvjs509.png" alt="wKioL1eOMSaD9UmLAACjGh-zvjs509.png" />


■下面是主要的代碼:

#pragma once
//實現紅黑樹的基本功能
/*
1.紅黑樹中的節點只能是紅色或者黑色
2.紅黑樹的根節點爲黑色
3.紅黑樹的左、右子樹的黑色節點個數是相同的
4.紅黑樹中紅色節點的兩個孩子節點必須都爲黑色節點
*/

enum color      //枚舉節點的兩種顏色
{
     RED,
     BLACK,
};

template <class K, class V>
struct RBTreeNode
{
     color _col;
     RBTreeNode<K, V>* _left;
     RBTreeNode<K, V>* _right;
     RBTreeNode<K, V>* _parent;
     K _key;
     V _value;
     
     RBTreeNode(const K& key, const V& value)
          :_key(key)
          , _value(value)
          , _left(NULL)
          , _right(NULL)
          , _parent(NULL)
          , _col(RED)          //顏色必須插入的是紅色,因爲要保證黑色節點的個數是平衡的
     { }
};

template <class K, class V>
class RBTree
{
     typedef RBTreeNode<K, V> Node;
public:
     RBTree()
          :_root(NULL)
     {}
     
     bool Insert(const K& key, const V& value)
     {
          if (_root == NULL)      //根節點爲空的情況,必須將根節點置爲黑色
          {
               _root = new Node(key, value);
               _root->_col = BLACK;
               return true;
          }
          Node* cur = _root;
          Node* parent = NULL;
          while (cur)
          {
               if (cur->_key < key)
               {
                    parent = cur;
                    cur = cur->_right;
               }
               else if (cur->_key > key)
               {
                    parent = cur;
                    cur = cur->_left;
               }
               else
               {
                    break;
               }
          }
          
          //尋找到數據該插入的位置
          if (parent->_key < key)
          {
               Node* tmp = new Node(key, value);
               parent->_right = tmp;
               tmp->_parent = parent;
          }
          else if (parent->_key > key)
          {
               Node* tmp = new Node(key, value);
               parent->_left = tmp;
               tmp->_parent = parent;
          }
          
      //處理(如果父節點爲黑色,則不用對樹進行調整,樹保持紅黑樹的狀態)
          while(cur != _root && parent->_col == RED)
          //插入的不是根節點,且父節點的顏色爲紅
          {
               Node* grandFather = parent->_parent;
               if (parent == grandFather->_left)
               {
                    Node* uncle = grandFather->_right;
                    //情況一:需要將祖父節點置爲紅色,將父親節點和叔叔節點置爲黑色,
                    //下次直接從祖父節點向上進行調整
                    if (uncle != NULL && uncle->_col == RED)    
                    {
                     grandFather->_col = RED;
                     parent->_col = BLACK;
                     uncle->_col = BLACK;
                     cur = grandFather;
                     parent = cur->_parent;
                    }
                    else
                    {
                     //情況二:需要先進行右單旋,然後將父親節點置爲黑色,祖父節點置爲紅色
                      //情況三:需要先進行左單旋,然後就會轉化爲情況二
                     if (cur == parent->_right && parent->_right != NULL)  //情況三左、右
                     {
                      _RotateL(parent);
                     }
                     parent->_col = BLACK;     
                     grandFather->_col = RED;
                     _RotateR(grandFather);
                    
                    }
               }
               else     //父親節點爲祖父節點的右節點
               {
                    Node* uncle = grandFather->_left;
                    //情況一:需要將祖父節點置爲紅色,將父親節點和叔叔節點置爲黑色,
                    //下次直接從祖父節點向上進行調整
                    if (uncle != NULL && uncle->_col == RED)
                    {
                         grandFather->_col = RED;
                         parent->_col = BLACK;
                         uncle->_col = BLACK;
                         cur = grandFather;
                         parent = cur->_parent;
                    }
                    else
                    {
                     //情況二:需要先進行左單旋,然後將父親節點置爲黑色,祖父節點置爲紅色
                     //情況三:需要進行右單旋,然後就會轉化爲情況二
                         if (cur == parent->_left && parent->_left != NULL)//情況三右、左
                         {
                              _RotateR(parent);
                         }
                         parent->_col = BLACK;
                         grandFather->_col = RED;
                         _RotateL(grandFather);
                    }
               }
          }
          _root->_col = BLACK;
          return true;
     }

     void InOrder()
     {
          _InOrder(_root);
          cout << endl;
     }
     
     bool Check()     //檢查是否爲紅黑樹
     {
          int countBlack = 0;
          Node* cur = _root;
          while (cur->_left != NULL)    //統計一條路徑上的黑色節點的數目
          {
               if (cur->_col == BLACK)
               {
                    countBlack++;
               }
               cur = cur->_left;
          }
          return _Check(_root, 0, countBlack);
     }
     
protected:
     bool _Check(Node* root, int blackNum, int curBalanceNum)
     {
          if (root == NULL)
          {
               return false;
          }
          if (root->_parent != NULL && root->_col == BLACK)   
          {
               if (root->_parent->_col == RED)
               {
                    return true;
               }
          }
          if (root->_left == NULL && root->_right == NULL)     //遞歸到葉子節點是的黑色節點數目是否相等
          {
               if (blackNum == curBalanceNum)
               {
                    return true;
               }
               else
               {
                    return false;
               }
          }
          return _Check(root->_left, blackNum++, curBalanceNum)
           && _Check(root->_right, blackNum++, curBalanceNum);
     }

     void _InOrder(Node* root)
     {
          if (root == NULL)
          {
               return;
          }
          _InOrder(root->_left);
          cout << root->_key <<":"<<root->_col<<endl;
          _InOrder(root->_right);
     }

     void _RotateL(Node*& parent)     //左單旋
     {
          Node* SubR = parent->_right;    //新建兩個節點指針
          Node* SubRL = SubR->_left;
          parent->_right = SubRL;        //進行調整
          if (SubRL)
          {
               SubRL->_parent = parent;
          }
          SubR->_left = parent;
          SubR->_parent = parent->_parent;
          parent->_parent = SubR;
          parent = SubR;
          if (parent->_parent == NULL)     //parent爲根節點的情況
          {
               _root = parent;
          }
          else                             //parent不爲根節點
          {
               Node* ppNode = parent->_parent;
               if (ppNode->_key > parent->_key)
               {
                    ppNode->_left = parent;
               }
               else
               {
                    ppNode->_right = parent;
               }
          }
     }

     void _RotateR(Node*& parent)     //右單旋
     {
          Node* SubL = parent->_left;   //新建兩個節點指針
          Node* SubLR = SubL->_right;
          parent->_left = SubLR;    //進行調整
          if (SubLR)
          {
               SubLR->_parent = parent;
          }
          SubL->_right = parent;
          SubL->_parent = parent->_parent;
          parent->_parent = SubL;
          parent = SubL;
          if (parent->_parent == NULL)     //parent爲根節點的情況
          {
               _root = parent;
          }
          else                             //parent不爲根節點
          {
               Node* ppNode = parent->_parent;
               if (ppNode->_key > parent->_key)
               {
                    ppNode->_left = parent;
               }
               else
               {
                    ppNode->_right = parent;
               }
          }
     }
     
protected:
     Node* _root;
};

void Test()
{
     RBTree<int, int> ht;
     ht.Insert(5, 1);
     ht.Insert(9, 1);
     ht.Insert(3, 1);
     ht.Insert(1, 1);
     ht.Insert(8, 1);
     ht.Insert(2, 1);
     ht.Insert(4, 1);
     ht.Insert(6, 1);
     ht.Insert(7, 1);
     
     ht.InOrder();
     cout<<ht.Check()<<endl;
}






本文出自 “無心的執着” 博客,請務必保留此出處http://10740590.blog.51cto.com/10730590/1827889

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章