資料結構之——紅/黑樹狀結構

來源:互聯網
上載者:User

標籤:include   平衡   black   葉子   紅/黑樹狀結構   

    紅/黑樹狀結構是一棵二叉搜尋樹,它在每個節點上增加了一個儲存位來表示節點的顏色,可以是red或black。通過對任何一條從根到葉子簡單路徑上的顏色來約束,紅/黑樹狀結構保證最長路徑不超過最短路徑的兩倍,因而近似於平衡。


紅/黑樹狀結構是滿足下面紅黑性質的二叉搜尋樹:

  1. 每個節點,不是紅色就是黑色的

  2. 根節點是黑色的

  3. 如果一個節點是紅色的,則它的兩個子節點是黑色的(沒有連續的紅節點)

  4. 對每個節點,從該節點到其所有後代分葉節點的簡單路徑上,均包含相同數目的黑色節點。(每條路徑的黑色節點的數量相等)


這裡分析一下為什麼紅/黑樹狀結構能保證最長路徑不超過最短路徑的兩倍:首先因為第4條約束條件假設一棵樹如下所示:

   B

 B   B

B      B    B表示為黑色結點,那麼要在其中插入任何一個黑色結點就需要保證第4條約定,而如果要插入紅色結點,則第3條約束又使得紅色結點只能插在黑色結點之間,因此一條路徑最多變成:

   B

 B   R

B      B

        R

         B      因此,最長路徑不超過最短路徑的兩倍,也就保證了搜尋的效率;



下面是實現紅/黑樹狀結構的插入過程:

#pragma once#include <iostream>using namespace std;//結點的顏色 紅or黑enum Color{RED,BLACK};//結點結構體template <class K, class V>struct RBTreeNode{K _key;V _val;RBTreeNode<K, V>* _left;RBTreeNode<K, V>* _right;RBTreeNode<K, V>* _parent;Color _col;RBTreeNode(const K& key, const V& val):_key(key),_val(val),_left(NULL),_right(NULL),_parent(NULL),_col(RED){}};//紅/黑樹狀結構類template <class K, class V>class RBTree{typedef RBTreeNode<K, V> Node;public:RBTree():_root(NULL){}~RBTree(){_Clear(_root);}//插入結點bool Insert(const K& key, const V& val){if(_root == NULL)//如果根結點為NULL,建立新的結點為根結點返回true{_root = new Node(key, val);_root->_col = BLACK;return true;}//如果根結點不為NULL,則遍曆樹直到找到合適的插入位置Node* cur = _root;Node* prev = cur;while(cur != NULL){if(cur->_key == key)//如果樹中已經有該結點,則返回falsereturn false;else if(cur->_key > key)//如果關索引值小於結點的關索引值,則去左子樹找{prev = cur;cur = cur->_left;}else//否則關索引值大於結點的關索引值,去右子樹找{prev = cur;cur = cur->_right;}}//迴圈結束,找到了合適的插入位置,判斷應該插入到結點的左邊還是右邊Node* tmp = new Node(key, val);if(prev->_key > key)prev->_left = tmp;elseprev->_right = tmp;tmp->_parent = prev;//插入結點之後,就要開始判斷目前的樹是否符合紅/黑樹狀結構的性質while((tmp != _root) && (prev->_col == RED)){Node* grandfather = prev->_parent;//提取出tmp的祖父結點if(grandfather->_left == prev)//如果prev是grandfather的左結點{//第一種情況//tmp為紅,prev為紅,grandfather為黑,uncle存在且為紅//則將prev,uncle改為黑,grandfather改為紅,然後把grandfather當成tmp,繼續向上調整。Node* uncle = grandfather->_right;if(uncle != NULL && uncle->_col == RED){prev->_col = BLACK;uncle->_col = BLACK;grandfather->_col = RED;tmp = grandfather;prev = tmp->_parent;}else//第二種情況:tmp為紅,prev為紅,grandfather為黑,uncle不存在/uncle為黑//prev為grandfather的左孩子,tmp為prev的左孩子,則進行右單旋轉;//prev、grandfather變色--prev變黑,grandfather變紅{//第三種情況//tmp為紅,prev為紅,grandfather為黑,uncle不存在/uncle為黑//prev為grandfather的左孩子,tmp為prev的右孩子,則針對prev做左單旋轉;//則轉換成了情況二if(prev->_right == tmp){_RotateL(prev);swap(tmp, prev);}_RotateR(grandfather);//進行右單旋prev->_col = BLACK;grandfather->_col = RED;break;}}else//當perv是grandfather的右結點的時候,和上面的情況相反{//第一種情況//tmp為紅,prev為紅,grandfather為黑,uncle存在且為紅//則將prev,uncle改為黑,grandfather改為紅,然後把grandfather當成tmp,繼續向上調整。Node* uncle = grandfather->_left;if(uncle != NULL && uncle->_col == RED){prev->_col = BLACK;uncle->_col = BLACK;grandfather->_col = RED;tmp = grandfather;prev = tmp->_parent;}else//第二種情況:tmp為紅,prev為紅,grandfather為黑,uncle不存在/uncle為黑//prev為grandfather的右孩子,tmp為prev的右孩子,則進行左單旋轉//prev、grandfather變色--prev變黑,grandfather變紅{//第三種情況//tmp為紅,prev為紅,grandfather為黑,uncle不存在/uncle為黑//prev為grandfather的右孩子,tmp為prev的左孩子,則針對prev做右單旋轉//則轉換成了情況二if(prev->_left == tmp){_RotateR(prev);swap(tmp, prev);}_RotateL(grandfather);//進行右單旋prev->_col = BLACK;grandfather->_col = RED;break;}}}//如果根結點被調整成了紅色,將其改為黑色,並會不影響左右黑結點的個數if(_root->_col == RED)_root->_col = BLACK;return true;}void InOrder(){_InOrder(_root);cout<<endl;}/*bool Find(const K& key){}*/private:void _Clear(Node* root){if(root == NULL)return;_Clear(root->_left);_Clear(root->_right);delete root;root = NULL;}void _RotateL(Node* parent)//左單旋    {        Node* subR = parent->_right;        Node* subRL = subR->_left;         parent->_right = subRL;        if (subRL != NULL)            subRL->_parent = parent;                 Node* ppNode = parent->_parent;         subR->_left = parent;        parent->_parent = subR;         if (ppNode == NULL)            _root = subR;        else        {            if (ppNode->_left == parent)                ppNode->_left = subR;            else                ppNode->_right = subR;        }subR->_parent = ppNode;    }    void _RotateR(Node* parent)//右單旋    {        Node* subL = parent->_left;        Node* subLR = subL->_right;         parent->_left = subLR;        if (subLR != NULL)            subLR->_parent = parent;         Node* ppNode = parent->_parent;        subL->_right = parent;        parent->_parent = subL;         if (ppNode == NULL)            _root = subL;        else        {            if (ppNode->_left == parent)                ppNode->_left = subL;            else                ppNode->_right = subL;        }subL->_parent = ppNode;}void _InOrder(Node* root){if(root != NULL){_InOrder(root->_left);cout<<root->_key<<" ";_InOrder(root->_right);}}private:Node* _root;};void Test(){int arr[] = {3, 4, 6, 1, 7, 2, 8};RBTree<int, int> t;for(int i = 0; i < sizeof(arr)/sizeof(arr[0]); ++i)t.Insert(arr[i], i);t.InOrder();}


運行程式:

650) this.width=650;" src="http://s5.51cto.com/wyfs02/M00/85/3F/wKioL1eeGTLBZhTBAABpj_8nBYA643.png-wh_500x0-wm_3-wmp_4-s_3537116884.png" title="RBTree.png" alt="wKioL1eeGTLBZhTBAABpj_8nBYA643.png-wh_50" />



《完》


本文出自 “敲完代碼好睡覺zzz” 部落格,請務必保留此出處http://2627lounuo.blog.51cto.com/10696599/1832660

資料結構之——紅/黑樹狀結構

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.