紅黑樹是一棵二叉搜索樹,它在每個節點上增加了一個存儲位來表示節點的顏色,可以是Red或Black。通過對任何一條從根到葉子簡單路徑上的顏色來約束,紅黑樹保證最長路徑不超過最短路徑的兩倍,因而近似於平衡。
紅黑樹是滿足下面紅黑性質的二叉搜索樹
每個節點,不是紅色就是黑色的
根節點是黑色的
如果一個節點是紅色的,則它的兩個子節點是黑色的(沒有連續的紅節點)
對每個節點,從該節點到其所有後代葉節點的簡單路徑上,均包含相同數目的黑色節點。(每條路徑的黑色節點的數量相等)
每個葉子節點都是黑色的(這裏的葉子節點是指的NIL節點(空節點))
插入的幾種情況
ps:cur爲當前節點,p爲父節點,g爲祖父節點,u爲叔叔節點
1.第一種情況
cur爲紅,p爲紅,g爲黑,u存在且爲紅
則將p,u改爲黑,g改爲紅,然後把g當成cur,繼續向上調整。
2.第二種情況
cur爲紅,p爲紅,g爲黑,u不存在/u爲黑
p爲g的左孩子,cur爲p的左孩子,則進行右單旋轉;相反,p爲g的右孩子,cur爲p的右孩子,則進行左單旋轉
p、g變色--p變黑,g變紅
3.第三種情況
cur爲紅,p爲紅,g爲黑,u不存在/u爲黑
p爲g的左孩子,cur爲p的右孩子,則針對p做左單旋轉;相反,p爲g的右孩子,cur爲p的左孩子,則針對p做右單旋轉
則轉換成了情況2
#pragma once
#include<iostream>
using namespace std;
enum Colour
{
RED,
BLACK,
};
template<class K,class V>
struct RBTreeNode
{
RBTreeNode<K, V>* _left;
RBTreeNode<K, V>* _right;
RBTreeNode<K, V>* _parent;
K _key;
V _value;
Colour _col;
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* parent = NULL;
Node* cur = _root;
while (cur)
{
if (cur->_key > key)
{
parent = cur;
cur = cur->_left;
}
else if (cur->_key < key)
{
parent = cur;
cur = cur->_right;
}
else
{
return false;
}
}
cur = new Node(key, value);
if (parent->_key < key)
{
parent->_right = cur;
cur->_parent = parent;
}
else
{
parent->_left = cur;
cur->_parent = parent;
}
while (cur != _root && parent->_col == RED)//grandfather肯定不爲空,根節點的顏色爲黑色
{
Node* grandfather = parent->_parent;
if (grandfather->_left == parent)//parent爲的grandfather左孩子
{
Node* uncle = grandfather->_right;
if (uncle && uncle->_col == RED)//uncle存在並且爲紅色的
{
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
cur = grandfather;
parent = cur->_parent;
}
else
{
if (cur = parent->_right)//cur爲parent的右孩子,先把它左單旋爲左孩子
{
RotateL(parent);
swap(parent, cur);
}
parent->_col = BLACK;
grandfather->_col = RED;
RotateR(grandfather);
break;
}
}
else
{
Node* uncle = grandfather->_left;
if (uncle && uncle->_col == RED)
{
parent->_col = uncle->_col = BLACK;
grandfather->_col = RED;
cur = grandfather;
parent = cur->_parent;
}
else
{
if (parent->_left == cur)
{
RotateR(parent);
swap(parent, cur);
}
parent->_col = BLACK;
grandfather->_col = RED;
RotateL(grandfather);
break;
}
}
}
_root->_col = BLACK;
}
void Inorder()
{
_Inorder(_root);
cout << endl;
}
bool IsBalance()
{
if (_root == NULL)
{
return true;
}
if (_root->_col == RED)//根節點必須是黑色的
{
return false;
}
Node* cur = _root;
int k = 0;
while (cur)
{
if (cur->_col == BLACK)
{
k++;
}
cur = cur->_left;
}
int count = 0;
return _IsBalance(_root, k, count);
}
Node* Find(const K& key)
{
if (_root == NULL)
{
return NULL;
}
Node* cur = _root;
while (cur)
{
if (cur->_key > key)
{
cur = cur->_left;
}
else if (cur->_key < key)
{
cur = cur->_right;
}
else
{
return cur;
}
}
return NULL;
}
protected:
bool _IsBalance(Node* root, const int k, int count)
{
if (root == NULL)
{
return true;
}
if (root->_col == RED && root->_parent->_col == RED)
{
cout << "出現連續的紅色節點" << root->_key << endl;
return false;
}
if (root->_col == BLACK)
{
++count;
}
if (root->_left == NULL && root->_right == NULL && count != k)
{
cout << "黑色節點個數不相等" << root->_key << endl;
return false;
}
return _IsBalance(root->_left, k, count) && _IsBalance(root->_right, k, count);
}
void _Inorder(Node* root)
{
if (root == NULL)
{
return;
}
_Inorder(root->_left);
cout << root->_key << " ";
_Inorder(root->_right);
}
void RotateL(Node* parent)
{
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
if (subRL)
{
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)
{
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;
}
protected:
Node* _root;
};