目錄
概念
性質
節點定義
紅黑樹的插入
完整代碼
概念
紅黑樹,是一種二叉搜索樹,但在每個結點上增加一個存儲位表示結點的顏色,可以是Red或Black。通過對任何一條從根到葉子的路徑上各個結點著色方式的限制,紅黑樹確保沒有一條路徑會比其他路徑長出倆倍,因而是接近平衡的。
下面就是一個紅黑樹:?
注:從根節點到NIL節點才是才算是一條路徑。
性質
1.每個結點不是紅色就是黑色
2.根節點是黑色的
3.如果一個節點是紅色的,則它的兩個孩子結點是黑色的
4.對于每個結點,從該結點到其所有后代葉結點的簡單路徑上,均包含相同數目的黑色結點5.每個葉子結點都是黑色的(此處的葉子結點指的是空結點)
節點定義
enum Colour
{RED,BLACK
};template<class K, class V>
struct RBTreeNode
{RBTreeNode<K, V>* _left;RBTreeNode<K, V>* _right;RBTreeNode<K, V>* _parent;pair<K, V> _kv;Colour _col;RBTreeNode(const pair<K, V>& kv):_left(nullptr), _right(nullptr), _parent(nullptr), _kv(kv), _col(RED){}
};
?通過上面的代碼不難發現,我們將新創建的節點設置為紅色,為什么不設置成黑色呢?
根據紅黑樹的性質4,我們知道,每條路徑上黑色節點的數目是相等的,倘若我們在插入節點時,插入的是黑色節點,那么將影響整棵樹;插入的是紅色節點,不至于影響整棵樹,因為如果新插入節點的父節點是黑色,將不需要進行調整;如果新插入節點的父節點是紅色,只需要進行相關調整即可。
總的來說,新插入節點是紅色,影響范圍更小,利于編碼實現,更方便。
紅黑樹的插入
1.按照二叉搜索樹的規則插入節點;
2.判斷紅黑樹的結構是否被破壞。
因為新節點的默認顏色是紅色,因此:如果其父節點是黑色,就沒有違反紅黑樹任何行者,則不需要調整;但當新插入節點的父節點是紅色時,就違反了性質三(不能出現連續的紅色節點),此時需要對紅黑樹分情況來討論:
【約定】:cur為當前節點,p為父節點,g為祖父節點,u為叔叔節點。
情況一:cur為紅,p為紅,g為黑,u存在且為紅
解決方式:將p,u改為黑,g改為紅,然后把g改為cur,繼續向上調整。
情況二:cur為紅,p為紅,g為黑,u不存在 / u存在且為黑
解決方式:p為g的左孩子,cur為p的左孩子,則進行右單旋,p改為黑色,g改為紅色;
? ? ? ? ? ? ? ? ? p為g的右孩子,cur為p的右孩子,則進行左單旋,p改為黑色,g改為紅色。
此時u有兩種情況:
1.u節點不存在,此時cur一定是新增節點,因為如果cur不是新插入節點,則cur和p一定有一個節點的顏色是黑色的,就不滿足性質四(每條路徑黑色節點個數相同)。
2.u節點存在,則其一定是黑色的.
情況三:cur為紅,p為紅,g為黑,u不存在 / u存在且為黑
解決方式:p為g的左孩子,cur為p的右孩子,則進行左單旋,再右單旋,? p改為黑色,g改為紅色;
? ? ? ? ? ? ? ? ? p為g的右孩子,cur為p的左孩子,則進行右單旋,再左單旋,? p改為黑色,g改為紅色。
此時u有兩種情況:
1.u節點不存在,此時cur一定是新增節點,因為如果cur不是新插入節點,則cur和p一定有一個節點的顏色是黑色的,就不滿足性質四(每條路徑黑色節點個數相同)。
2.u節點存在,則其一定是黑色的.
插入代碼實現?
bool Insert(const pair<K, V>& kv)
{if (_root == nullptr){_root = new Node(kv);_root->_col = BLACK;return true;}Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else if (cur->_kv.first > kv.first){parent = cur;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){// g// p u// cNode* uncle = grandfather->_right;if (uncle && uncle->_col == RED){// 變色parent->_col = uncle->_col = BLACK;grandfather->_col = RED;// 繼續往上更新處理cur = grandfather;parent = cur->_parent;}else{if (cur == parent->_left){// 單旋// g// p// cRotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{// 雙旋// g// p// cRotateL(parent);RotateR(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}else // parent == grandfather->_right{// g// u p // c//Node* uncle = grandfather->_left;if (uncle && uncle->_col == RED){// 變色parent->_col = uncle->_col = BLACK;grandfather->_col = RED;// 繼續往上處理cur = grandfather;parent = cur->_parent;}else{if (cur == parent->_right){RotateL(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{// g// u p // c//RotateR(parent);RotateL(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}}_root->_col = BLACK;return true;
}
完整代碼
#pragma onceenum Colour
{RED,BLACK
};template<class K, class V>
struct RBTreeNode
{RBTreeNode<K, V>* _left;RBTreeNode<K, V>* _right;RBTreeNode<K, V>* _parent;pair<K, V> _kv;Colour _col;RBTreeNode(const pair<K, V>& kv):_left(nullptr), _right(nullptr), _parent(nullptr), _kv(kv), _col(RED){}
};template<class K, class V>
class RBTree
{typedef RBTreeNode<K, V> Node;
public:bool Insert(const pair<K, V>& kv){if (_root == nullptr){_root = new Node(kv);_root->_col = BLACK;return true;}Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else if (cur->_kv.first > kv.first){parent = cur;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){// g// p u// cNode* uncle = grandfather->_right;if (uncle && uncle->_col == RED){// 變色parent->_col = uncle->_col = BLACK;grandfather->_col = RED;// 繼續往上更新處理cur = grandfather;parent = cur->_parent;}else{if (cur == parent->_left){// 單旋// g// p// cRotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{// 雙旋// g// p// cRotateL(parent);RotateR(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}else // parent == grandfather->_right{// g// u p // c//Node* uncle = grandfather->_left;if (uncle && uncle->_col == RED){// 變色parent->_col = uncle->_col = BLACK;grandfather->_col = RED;// 繼續往上處理cur = grandfather;parent = cur->_parent;}else{if (cur == parent->_right){RotateL(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{// g// u p // c//RotateR(parent);RotateL(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}}_root->_col = BLACK;return true;}void RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;subR->_left = parent;Node* parentParent = parent->_parent;parent->_parent = subR;if (subRL)subRL->_parent = parent;if (_root == parent){_root = subR;subR->_parent = nullptr;}else{if (parentParent->_left == parent){parentParent->_left = subR;}else{parentParent->_right = subR;}subR->_parent = parentParent;}}void RotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR)subLR->_parent = parent;Node* parentParent = parent->_parent;subL->_right = parent;parent->_parent = subL;if (_root == parent){_root = subL;subL->_parent = nullptr;}else{if (parentParent->_left == parent){parentParent->_left = subL;}else{parentParent->_right = subL;}subL->_parent = parentParent;}}void InOrder(){_InOrder(_root);cout << endl;}void _InOrder(Node* root){if (root == nullptr)return;_InOrder(root->_left);cout << root->_kv.first << " ";_InOrder(root->_right);}// 根節點->當前節點這條路徑的黑色節點的數量bool Check(Node* root, int blacknum, const int refVal){if (root == nullptr){//cout << balcknum << endl;if (blacknum != refVal){cout << "存在黑色節點數量不相等的路徑" << endl;return false;}return true;}if (root->_col == RED && root->_parent->_col == RED){cout << "有連續的紅色節點" << endl;return false;}if (root->_col == BLACK){++blacknum;}return Check(root->_left, blacknum, refVal)&& Check(root->_right, blacknum, refVal);}bool IsBalance(){if (_root == nullptr)return true;if (_root->_col == RED)return false;//參考值int refVal = 0;Node* cur = _root;while (cur){if (cur->_col == BLACK){++refVal;}cur = cur->_left;}int blacknum = 0;return Check(_root, blacknum, refVal);}private:Node* _root = nullptr;
};