您好,登錄后才能下訂單哦!
紅黑樹是一棵二叉搜索樹,它在每個節(jié)點上增加了一個存儲位來表示節(jié)點的顏色,可以是red或black。通過對任何一條從根到葉子簡單路徑上的顏色來約束,紅黑樹保證最長路徑不超過最短路徑的兩倍,因而近似于平衡。
紅黑樹是滿足下面紅黑性質(zhì)的二叉搜索樹:
每個節(jié)點,不是紅色就是黑色的
根節(jié)點是黑色的
如果一個節(jié)點是紅色的,則它的兩個子節(jié)點是黑色的(沒有連續(xù)的紅節(jié)點)
對每個節(jié)點,從該節(jié)點到其所有后代葉節(jié)點的簡單路徑上,均包含相同數(shù)目的黑色節(jié)點。(每條路徑的黑色節(jié)點的數(shù)量相等)
這里分析一下為什么紅黑樹能保證最長路徑不超過最短路徑的兩倍:首先因為第4條約束條件假設(shè)一棵樹如下所示:
B
B B
B B B表示為黑色結(jié)點,那么要在其中插入任何一個黑色結(jié)點就需要保證第4條約定,而如果要插入紅色結(jié)點,則第3條約束又使得紅色結(jié)點只能插在黑色結(jié)點之間,因此一條路徑最多變成:
B
B R
B B
R
B 因此,最長路徑不超過最短路徑的兩倍,也就保證了搜索的效率;
下面是實現(xiàn)紅黑樹的插入過程:
#pragma once #include <iostream> using namespace std; //結(jié)點的顏色 紅or黑 enum Color { RED, BLACK }; //結(jié)點結(jié)構(gòu)體 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); } //插入結(jié)點 bool Insert(const K& key, const V& val) { if(_root == NULL)//如果根結(jié)點為NULL,創(chuàng)建新的結(jié)點為根結(jié)點返回true { _root = new Node(key, val); _root->_col = BLACK; return true; } //如果根結(jié)點不為NULL,則遍歷樹直到找到合適的插入位置 Node* cur = _root; Node* prev = cur; while(cur != NULL) { if(cur->_key == key)//如果樹中已經(jīng)有該結(jié)點,則返回false return false; else if(cur->_key > key)//如果關(guān)鍵值小于結(jié)點的關(guān)鍵值,則去左子樹找 { prev = cur; cur = cur->_left; } else//否則關(guān)鍵值大于結(jié)點的關(guān)鍵值,去右子樹找 { prev = cur; cur = cur->_right; } } //循環(huán)結(jié)束,找到了合適的插入位置,判斷應(yīng)該插入到結(jié)點的左邊還是右邊 Node* tmp = new Node(key, val); if(prev->_key > key) prev->_left = tmp; else prev->_right = tmp; tmp->_parent = prev; //插入結(jié)點之后,就要開始判斷目前的樹是否符合紅黑樹的性質(zhì) while((tmp != _root) && (prev->_col == RED)) { Node* grandfather = prev->_parent;//提取出tmp的祖父結(jié)點 if(grandfather->_left == prev)//如果prev是grandfather的左結(jié)點 { //第一種情況 //tmp為紅,prev為紅,grandfather為黑,uncle存在且為紅 //則將prev,uncle改為黑,grandfather改為紅,然后把grandfather當(dāng)成tmp,繼續(xù)向上調(diào)整。 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的左孩子,則進行右單旋轉(zhuǎn); //prev、grandfather變色--prev變黑,grandfather變紅 { //第三種情況 //tmp為紅,prev為紅,grandfather為黑,uncle不存在/uncle為黑 //prev為grandfather的左孩子,tmp為prev的右孩子,則針對prev做左單旋轉(zhuǎn); //則轉(zhuǎn)換成了情況二 if(prev->_right == tmp) { _RotateL(prev); swap(tmp, prev); } _RotateR(grandfather);//進行右單旋 prev->_col = BLACK; grandfather->_col = RED; break; } } else//當(dāng)perv是grandfather的右結(jié)點的時候,和上面的情況相反 { //第一種情況 //tmp為紅,prev為紅,grandfather為黑,uncle存在且為紅 //則將prev,uncle改為黑,grandfather改為紅,然后把grandfather當(dāng)成tmp,繼續(xù)向上調(diào)整。 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的右孩子,則進行左單旋轉(zhuǎn) //prev、grandfather變色--prev變黑,grandfather變紅 { //第三種情況 //tmp為紅,prev為紅,grandfather為黑,uncle不存在/uncle為黑 //prev為grandfather的右孩子,tmp為prev的左孩子,則針對prev做右單旋轉(zhuǎn) //則轉(zhuǎn)換成了情況二 if(prev->_left == tmp) { _RotateR(prev); swap(tmp, prev); } _RotateL(grandfather);//進行右單旋 prev->_col = BLACK; grandfather->_col = RED; break; } } } //如果根結(jié)點被調(diào)整成了紅色,將其改為黑色,并會不影響左右黑結(jié)點的個數(shù) 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(); }
運行程序:
《完》
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。