您好,登錄后才能下訂單哦!
紅黑樹又稱二叉搜索樹,它主要是通過紅和黑兩種顏色(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)
(2)
(3)
■下面是主要的代碼:
#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; }
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。