用c++實現紅黑樹的判斷、插入、遍歷操作
阿新 • • 發佈:2019-02-06
紅黑樹
紅黑樹是一棵二叉搜尋樹,它在每個節點上增加了一個儲存位來表示節點的顏色,可以是Red或Black。通過對任何一條從根到葉子簡單路徑上的顏色來約束,紅黑樹保證最長路徑不超過最短路徑的兩倍,因而近似於平衡。
紅黑樹是滿足下面紅黑性質的二叉搜尋樹:
1. 每個節點,不是紅色就是黑色的;
2. 根節點是黑色的;
3. 如果一個節點是紅色的,則它的兩個子節點是黑色的;
4. 對每個節點,從該節點到其所有後代葉節點的簡單路徑上,均包含相同數目的黑色節點;
5. 每個葉子節點都是黑色的(這裡的葉子節點是指的空節點)
思考:為什麼滿足上面的顏色約束性質,紅黑樹能保證最長路徑不超過最短路徑的兩倍?
一、判斷是否是紅黑樹:
//判斷是否是紅黑樹 bool isRBTree() { int BlackNodeNum = 0; int curBlackNodeNum = 0; Node* cur = _root; while (cur) { if (cur->_col == BLACK) { BlackNodeNum++; } cur = cur->_left; } return _isRBTree(_root, BlackNodeNum, curBlackNodeNum); }
bool _isRBTree(Node* root, int BlackNodeNum, int curBlackNodeNum) { if (root == NULL) { return true; } if (root->_col == BLACK) { curBlackNodeNum++; } if (BlackNodeNum == curBlackNodeNum) { if (root->_parent == NULL) { return true; } else if (root->_col == RED && root->_col == root->_parent->_col) { return false; } else { return true; } } return _isRBTree(root->_left, BlackNodeNum, curBlackNodeNum) && _isRBTree(root->_right, BlackNodeNum, curBlackNodeNum); }
二、紅黑樹的中序遍歷:
//中序遍歷
void InOrder()
{
_InOrder(_root);
}
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;
}
subR->_left = parent;
subR->_parent = parent->_parent;
parent->_parent = subR;
parent = subR;
if (parent->_parent == NULL)
{
_root = parent;
}
else if (parent->_parent->_key > parent->_key)
{
parent->_parent->_left = parent;
}
else if ( parent->_parent->_key<parent->_key )
{
parent->_parent->_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)
{
_root = parent;
}
else if (parent->_parent->_key > parent->_key)
{
parent->_parent->_left = parent;
}
else if (parent->_parent->_key < parent->_key)
{
parent->_parent->_right = parent;
}
}
五、插入的三種情況
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
上面已經把每種情況基本列出來了,其他相反的情況類似,反過來寫一下就行了,具體詳細過程參考程式碼。
//紅黑樹的插入操作
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;
}
}
//插入位置
if (parent->_key >key)
{
cur = new Node(key, value);
parent->_left = cur;
cur->_parent = parent;
}
else if (parent->_key < key)
{
cur = new Node(key, value);
parent->_right = cur;
cur->_parent = parent;
}
//插入以後,進行調整
while (cur != _root && parent->_col == RED)
{
Node* grandfather = parent->_parent;
Node* uncle = NULL;
//左邊的情況
if (parent == grandfather->_left)
{
//情況一
uncle = grandfather->_right;
if (uncle && uncle->_col == RED)
{
//1. 不需要旋轉
if (cur == parent->_left)
{
grandfather->_col = RED;
parent->_col = BLACK;
uncle->_col = BLACK;
cur = grandfather;
parent = cur->_parent;
}
//2.需要旋轉
else if (cur == parent->_right)
{
RotateL(parent);
grandfather->_col = RED;
parent->_col = BLACK;
uncle->_col = BLACK;
cur = grandfather;
parent = cur->_parent;
}
}
//情況二,三
else if (uncle == NULL || (uncle && uncle->_col == BLACK))
{
if (cur == parent->_right)
{
RotateL(parent);
}
parent->_col = BLACK;
grandfather->_col = RED;
RotateR(grandfather);
break;
}
}
//右邊的情況
else if (parent == grandfather->_right)
{
//情況一
uncle = grandfather->_left;
if (uncle && uncle->_col == RED)
{
//1.不需要旋轉
if (cur == parent->_right)
{
uncle->_col = BLACK;
grandfather->_col = RED;
parent->_col = BLACK;
cur = grandfather;
parent = cur->_parent;
}
//2.需要旋轉
else if (cur == parent->_left)
{
uncle->_col = BLACK;
grandfather->_col = RED;
parent->_col = BLACK;
RotateR(parent);
cur = grandfather;
parent = cur->_parent;
}
}
//情況二,三
else if (uncle == NULL || (uncle && uncle->_col == BLACK))
{
if (cur == parent->_left)
{
RotateR(parent);
}
parent->_col = BLACK;
grandfather->_col = RED;
RotateL(grandfather);
break;
}
}
}
_root->_col = BLACK;
return true;
}
紅黑樹和AVL樹的比較:
紅黑樹和AVL樹都是高效的平衡二叉樹,增刪查改的時間複雜度都是O(lg(N)),紅黑樹的不追求完全平衡,保證最長路徑不超過最短路徑的2倍,相對而言,降低了旋轉的要求,所以效能會優於AVL樹,所以實際運用中紅黑樹更多。完整程式碼及測試用例:
#include<iostream>
using namespace std;
enum colour
{
RED,
BLACK,
};
template<class K, class V>
struct RBTreeNode
{
int _col;
K _key;
V _value;
RBTreeNode<K, V>* _left;
RBTreeNode<K, V>* _right;
RBTreeNode<K, V>* _parent;
RBTreeNode(const K& key, const V& value)
:_key(key)
, _value(value)
, _col(RED)
, _left(NULL)
, _right(NULL)
, _parent(NULL)
{}
};
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;
}
}
//插入位置
if (parent->_key >key)
{
cur = new Node(key, value);
parent->_left = cur;
cur->_parent = parent;
}
else if (parent->_key < key)
{
cur = new Node(key, value);
parent->_right = cur;
cur->_parent = parent;
}
//插入以後,進行調整
while (cur != _root && parent->_col == RED)
{
Node* grandfather = parent->_parent;
Node* uncle = NULL;
//左邊的情況
if (parent == grandfather->_left)
{
//情況一
uncle = grandfather->_right;
if (uncle && uncle->_col == RED)
{
//1. 不需要旋轉
if (cur == parent->_left)
{
grandfather->_col = RED;
parent->_col = BLACK;
uncle->_col = BLACK;
cur = grandfather;
parent = cur->_parent;
}
//2.需要旋轉
else if (cur == parent->_right)
{
RotateL(parent);
grandfather->_col = RED;
parent->_col = BLACK;
uncle->_col = BLACK;
cur = grandfather;
parent = cur->_parent;
}
}
//情況二,三
else if (uncle == NULL || (uncle && uncle->_col == BLACK))
{
if (cur == parent->_right)
{
RotateL(parent);
}
parent->_col = BLACK;
grandfather->_col = RED;
RotateR(grandfather);
break;
}
}
//右邊的情況
else if (parent == grandfather->_right)
{
//情況一
uncle = grandfather->_left;
if (uncle && uncle->_col == RED)
{
//1.不需要旋轉
if (cur == parent->_right)
{
uncle->_col = BLACK;
grandfather->_col = RED;
parent->_col = BLACK;
cur = grandfather;
parent = cur->_parent;
}
//2.需要旋轉
else if (cur == parent->_left)
{
uncle->_col = BLACK;
grandfather->_col = RED;
parent->_col = BLACK;
RotateR(parent);
cur = grandfather;
parent = cur->_parent;
}
}
//情況二,三
else if (uncle == NULL || (uncle && uncle->_col == BLACK))
{
if (cur == parent->_left)
{
RotateR(parent);
}
parent->_col = BLACK;
grandfather->_col = RED;
RotateL(grandfather);
break;
}
}
}
_root->_col = BLACK;
return true;
}
//判斷是否是紅黑樹
bool isRBTree()
{
int BlackNodeNum = 0;
int curBlackNodeNum = 0;
Node* cur = _root;
while (cur)
{
if (cur->_col == BLACK)
{
BlackNodeNum++;
}
cur = cur->_left;
}
return _isRBTree(_root, BlackNodeNum, curBlackNodeNum);
}
//中序遍歷
void InOrder()
{
_InOrder(_root);
}
protected:
bool _isRBTree(Node* root, int BlackNodeNum, int curBlackNodeNum)
{
if (root == NULL)
{
return true;
}
if (root->_col == BLACK)
{
curBlackNodeNum++;
}
if (BlackNodeNum == curBlackNodeNum)
{
if (root->_parent == NULL)
{
return true;
}
else if (root->_col == RED && root->_col == root->_parent->_col)
{
return false;
}
else
{
return true;
}
}
return _isRBTree(root->_left, BlackNodeNum, curBlackNodeNum) && _isRBTree(root->_right, BlackNodeNum, curBlackNodeNum);
}
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;
}
subR->_left = parent;
subR->_parent = parent->_parent;
parent->_parent = subR;
parent = subR;
if (parent->_parent == NULL)
{
_root = parent;
}
else if (parent->_parent->_key > parent->_key)
{
parent->_parent->_left = parent;
}
else if ( parent->_parent->_key<parent->_key )
{
parent->_parent->_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)
{
_root = parent;
}
else if (parent->_parent->_key > parent->_key)
{
parent->_parent->_left = parent;
}
else if (parent->_parent->_key < parent->_key)
{
parent->_parent->_right = parent;
}
}
protected:
Node* _root;
};
void TestRBtree()
{
RBTree<int, int>RBT;
int arr[10]= { 1, 2,5, 12, 16, 18, 26, 3, 99,666 };
for (int i = 0; i < 10; i++)
{
RBT.Insert(arr[i], i);
}
RBT.InOrder();
cout << endl;
cout << "isRBTree? ->:" << RBT.isRBTree() << endl;
}
int main()
{
TestRBtree();
system("pause");
return 0;
}
執行結果:
1 2 3 5 12 16 18 26 99 666
isRBTree? ->:1
請按任意鍵繼續. . .