紅黑樹的概念
紅黑樹,是一種二叉搜尋樹,但在每個結點上增加一個存儲位表示結點的顔色,可以是Red或Black。 通過 對任何一條從根到葉子的路徑上各個結點着色方式的限制,紅黑樹確定沒有一條路徑會比其他路徑長出倆倍,因而是接近平衡的。
紅黑樹的性質
- 每個結點不是紅色就是黑色
- 根節點是黑色的
- 如果一個節點是紅色的,則它的兩個孩子結點是黑色的
- 對于每個結點,從該結點到其所有後代葉結點的簡單路徑上,均包含相同數目的黑色結點
- 每個葉子結點都是黑色的(此處的葉子結點指的是空結點)
思考:為什麼滿足上面的性質,紅黑樹就能保證:其最長路徑中節點個數不會超過最短路徑節點個數的兩倍?
紅黑樹節點的定義
// 節點的顔色 enum Color{RED, BLACK}; // 紅黑樹節點的定義 template<class ValueType> struct RBTreeNode { RBTreeNode(const ValueType& data = ValueType(),Color color = RED) : _pLeft(nullptr) , _pRight(nullptr) , _pParent(nullptr) , _data(data) , _color(color) {} RBTreeNode<ValueType>* _pLeft; // 節點的左孩子 RBTreeNode<ValueType>* _pRight; // 節點的右孩子 RBTreeNode<ValueType>* _pParent; // 節點的雙親(紅黑樹需要旋轉,為了實作簡單給出該字段) ValueType _data; // 節點的值域 Color _color; // 節點的顔色 };
紅黑樹結構
為了後續實作關聯式容器簡單,紅黑樹的實作中增加一個頭結點,因為跟節點必須為黑色,為了與根節點進 行區分,将頭結點給成黑色,并且讓頭結點的 pParent 域指向紅黑樹的根節點,pLeft域指向紅黑樹中小的節點,_pRight域指向紅黑樹中大的節點。
紅黑樹的代碼:
#define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> #include<stdlib.h> #pragma once enum Color { RED, BLA, }; template<class K, class V> class RBTreeNode { RBTreeNode<K, V>* _left; RBTreeNode<K, V>* _right; RBTreeNode<K, V>* _parent; std::pair<K, V> _kv; Color _col; }; template<class K, class V> class RBTree { typedef RBTreeNode<K, V> Node; public: bool Insert(const std::pair<K, V>& kv) { if (_root == nullptr) { _root = new Node(kv); _root->_col = BLA; return true; } Node* parent = nullptr; Node* cur = _root; while (cur) { parent = cur; if (cur->_kv.first < kv.first) { cur = cur->_right; } else if (cur->_kv.first > kv.first) { cur = cur->_left; } else { return false; } } cur = new Node(kv); cur->_col = RED;//這不能選黑色,因為每條路徑的黑結點都是一樣的,如果插入黑的會違反規則 if (parent->_kv.first < kv.first) { parent->_right = cur; cur->_parent = parent; } else { parent->_left = cur; cur->_parent = parent; } //達到平衡 while (parent && parent->_col == RED) { Node* grandfather = parent->_parent; if (parent = grandfather->_left) { Node* uncle = grandfather->_right; if (uncle && uncle->_col == RED) { //第一種情況:變色 parent->_col = BLA; uncle->_col = BLA; grandfather->_col = RED; cur = granffather; parent = cur->_parent; } else//uncle不存在或者存在且為黑 { //第三種情況:雙旋->單旋 if (cur == parent->_right)//單旋 { RotateL(parent); swap(cur, parent);//旋轉之後cur和parent的位置發生了改變 } //第二種情況:單旋+變色 RotateR(grandfather); parent->_col = BLA; grandfather->_col = RED; } } else//parent = grandfarher->_right { Node* uncle = grandfather->_left; if (uncle && uncle->_col == RED) { //變色 parent->_col = BLA; uncle->_col = BLA; grandfather->_col = RED; cur = grandfather; parent = cur->_parent; } else { if (cur == parent->_left) { RotateR(parent); swap(cur, parent); } RotateL(grandfather); parent->_col = BLA; grandfather->_col = RED; } } } _root->_col = BLA; return true; } private: Node* _root = nullptr; }; int main() { system("pause"); return 0; }