紅黑樹又稱二叉搜索樹,它主要是經過紅和黑兩種顏色(red、black)來標識節點。經過對任何一條從根節點到葉子節點路徑上的節點顏色進行約束,紅黑樹保證最長路徑不超過最短路徑的兩倍,因此說:紅黑樹是近似於平衡的。java
■下面是紅黑樹的主要特色:linux
(1)紅黑樹的根節點是黑色的。ide
(2)紅黑樹中若一個節點是紅色的,則它的兩個子節點必須是黑色的。性能
(3)紅黑樹中從該節點到後代葉節點的路徑上,黑色節點數目是相同的。spa
◆紅黑樹的應用:指針
C++庫、linux內核、java庫等blog
◆紅黑樹與AVL樹的區別:遞歸
紅黑樹和AVL樹都是高效的平衡搜索樹,時間複雜度都是O(lgN);get
紅黑樹對平衡的要求不是特別高,它只須要知足最長路徑不超過最短路徑的兩倍,因此性能相對較高。it
■下面是紅黑樹中節點結構:
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; }