1、紅黑樹的性質(參考《算法導論》):
每個節點均有顏色屬性,且要麼爲紅色,要麼爲黑色;
根節點爲黑色;
紅色節點的子節點不可以爲紅色
對每個節點,從該節點到期子孫節點的所有路徑上包含相同數目的黑節點
2、紅黑樹節點的定義:
<span style="font-family:Courier New;">template <typename T>
class RBTNode
{
private:
T data;
char color;
RBTNode<T> *lchild;
RBTNode<T> *rchild;
RBTNode<T> *parent;
private:
RBTNode() : lchild(0), rchild(0), parent(0), color('R') {}
RBTNode(const T& elem) : data(elem), lchild(0), rchild(0), parent(0), color('R') {}
private:
template <typename T1>
friend class RBTree; // 紅黑樹
template <typename T1>
friend class RBTreeOperator; // 另一個類,僅用於測試,可以對紅黑樹進行遍歷
};</span>
<span style="font-family:Courier New;">3、紅黑樹類的定義:</span>
<span style="font-family:Courier New;">template <typename T>
class RBTree
{
public:
RBTree():root(0){}
~RBTree(){}
void insert(const T& elem); // 插入元素
void erase(const T& elem); // 刪除元素
bool find(const T& elem); // 查找元素
void clear(); // 清除節點
private:
typedef RBTNode<T>* pointer;
private:
pointer left_rotate(pointer p); // 節點左旋
pointer right_rotate(pointer p); // 節點右旋
pointer find_insert(const T& elem); // 定位待插入元素的父節點
pointer find_del(const T& elem); // 定位待刪除元素
pointer find_minimum(pointer p); // 定位以p爲根的子樹的最小元素
pointer find_successor(pointer p); // 定位中序遍歷時節點p的後繼元素,同find_minimum用於定位實際刪除的節點
void clear_node(pointer p); // 刪除節點p
private:
pointer root;
private:
template <typename T1>
friend class RBTreeOperator; // 同上
};</span>
<span style="font-family:Courier New;">// 以下爲類成員函數的實現</span>
<span style="font-family:Courier New;">template<typename T>
RBTNode<T>* RBTree<T>::left_rotate(RBTNode<T> *p) // 節點左旋,返回子樹的新根節點
{
if(!p || !p->rchild)
{
return p;
}
RBTNode<T> *q = p->rchild;
p->rchild = q->lchild;
if(p->rchild)
{
p->rchild->parent = p;
}
q->lchild = p;
q->parent = p->parent;
p->parent = q;
if(!q->parent)
{
root = q;
}
else
{
if(p == q->parent->lchild)
{
q->parent->lchild = q;
}
else
{
q->parent->rchild = q;
}
}
return q;
}
template <typename T>
RBTNode<T>* RBTree<T>::right_rotate(RBTNode<T> *p)
{
if(!p || !p->lchild)
{
return p;
}
RBTNode<T> *q = p->lchild;
p->lchild = q->rchild;
if(p->lchild)
{
p->lchild->parent = p;
}
q->rchild = p;
q->parent = p->parent;
p->parent = q;
if(!q->parent)
{
root = q;
}
else
{
if(p == q->parent->lchild)
{
q->parent->lchild = q;
}
else
{
q->parent->rchild = q;
}
}
return q;
}
template <typename T>
RBTNode<T>* RBTree<T>::find_insert(const T& elem)
{
RBTNode<T> *p(root), *q(root);
while(q)
{
p = q;
q = p->data < elem ? p->rchild : p->lchild;
}
return p;
}
template <typename T>
RBTNode<T>* RBTree<T>::find_del(const T& elem)
{
RBTNode<T> *p = root;
while(p)
{
if(p->data == elem)
{
break;
}
if(p->data < elem)
{
p = p->rchild;
}
else
{
p = p->lchild;
}
}
return p;
}
template <typename T>
RBTNode<T>* RBTree<T>::find_minimum(RBTNode<T> *p)
{
while(p && p->lchild)
{
p = p->lchild;
}
return p;
}
template <typename T>
RBTNode<T>* RBTree<T>::find_successor(RBTNode<T> *p) // 查找p於中序遍歷中的後繼結點
{
if(!p)
{
return p;
}
if(p->rchild)
{
return find_minimum(p->rchild);
}
else // 無右子節點,則向上尋找第一個爲其父節點的左孩子的節點q,則q的父節點即爲p的後繼
{
RBTNode<T> *q = p->parent;
while(q && p == q->rchild)
{
p = q;
q = q->parent;
}
return q;
}
}
template <typename T>
void RBTree<T>::clear_node(RBTNode<T> *node)
{
if(node)
{
clear_node(node->lchild);
clear_node(node->rchild);
delete node;
}
}
template <typename T>
void RBTree<T>::insert(const T& elem)
{
RBTNode<T> *p(new RBTNode<T>(elem)), *q(find_insert(elem)), *r(0);
p->parent = q;
if(!q) // 樹根爲空,則令新插入節點p爲樹根
{
root = p;
root->color = 'B';
return;
}
if(q->data < elem)
{
q->rchild = p;
}
else
{
q->lchild = p;
}
while(q && q != root && q->color == 'R') //p與其父節點q的顏色均爲紅色,違反定義
{
RBTNode<T> *node = q->parent;
if(q == node->lchild) // 若q爲其父節點的左孩子
{
r = node->rchild; // r爲p的叔父
if(r && r->color == 'R') // 若q與r的顏色均爲紅,則將二者顏色變黑,其父節點變紅,並將p指向該父節點,下一步循環
{
r->color = 'B';
q->color = 'B';
node->color = 'R';
p = node;
q = p->parent;</span>
<span style="font-family:Courier New;"><span style="white-space: pre;"> </span>continue;</span>
<span style="font-family:Courier New;"> <span style="white-space:pre"> </span>}</span>
<span style="font-family:Courier New;"> if(p == q->rchild) // 若p爲q的右孩子,則應將q左旋並交換地址,使得p爲q的左孩子
{
left_rotate(q);
p = q;
q = p->parent;
}
right_rotate(node); // 通過將node節點右旋以及node與q的顏色交換,使該子樹根節點爲黑色,同時消除了紅-紅父子衝突
q->color = 'B';
node->color = 'R';
}
else
{
r = node->lchild;
if(r && r->color == 'R')
{
r->color = 'B';
q->color = 'B';
node->color = 'R';
p = node;
q = p->parent;</span>
<span style="font-family:Courier New;"><span style="white-space:pre"> </span>continue;
}
else
{
if(p == q->lchild)
{
right_rotate(q);
p = q;
q = p->parent;
}
left_rotate(node);
q->color = 'B';
node->color = 'R';
}
}
}
root->color = 'B'; // 根節點染紅
}
template <typename T>
void RBTree<T>::erase(const T& elem)
{
RBTNode<T> *q(find_del(elem)), *p(0), *r(0), *node(0);
if(!q)
{
return;
}
if(!q->lchild || !q->rchild) // q孩子數少於2,則直接刪除q即可
{
node = q;
}
else // 否則刪除其後繼位置的節點node,node必然不會同時有左右兩個孩子
{
node = find_successor(q);
}
if(node != q) // 將node的值賦值到q
{
q->data = node->data;
}</span>
<span style="font-family:Courier New;"><span style="white-space:pre"> </span>// 以下代碼處理被刪除節點爲根節點或者無子節點的情況
q = node->parent;
p = (node->lchild ? node->lchild : node->rchild);
if(q)
{
if(node == q->lchild)
{
q->lchild = p;
}
else
{
q->rchild = p;
}
}
else
{
root = p;
}
if(!p)
{
delete node;
return;
}
else
{
p->parent = q;
}
if(node->color == 'B') // 若被刪除節點爲黑色,則其所在的路徑上少了一個黑色節點,需要矯正
{
while(p != root && p->color == 'B') // 循環條件:還未遇到紅色節點以染成黑色
{
q = p->parent;
if(p == q->lchild) // 若p爲其父節點q的左孩子
{
r = q->rchild; // r爲q的右孩子,p的兄弟節點
if(!r) // q只有一個孩子,無需處理該子樹,p上移一層
{
p = q;
continue;
}
if(r->color == 'R') // 若r爲紅色,則通過q的左旋以及r與q的顏色交換,轉換爲p的兄弟爲黑色的情況(後邊處理該情況)
{
r->color = 'B';
q->color = 'R';
left_rotate(q);
r = q->rchild;
</span><p><span style="font-family:Courier New;"> }</span></p><p><span style="font-family:Courier New;"><span style="white-space:pre"> </span>// 以下爲p的兄弟節點r爲黑色的情況,分三種情況處理:</span></p>
<span style="font-family:Courier New;"> if((!r->lchild ||r->lchild->color == 'B') && (!r->rchild || r->rchild->color == 'B')) // 1)r的子節點均不爲紅色,則將r染成<span style="white-space:pre"> </span>紅色,使得q向下缺少一層黑色,故可將p指向q,上移
{
r->color = 'R';
p = q;
}
else
{
if(!r->rchild || r->rchild->color == 'B') // 2)r的右子節點爲空或黑色,通過旋轉使p的兄弟右孩子爲紅色
{
r->color = 'R';
r->lchild->color = 'B';
r = right_rotate(r);
}
r->color = q->color; // 3)r的右子節點爲紅色,將q左旋並通過顏色交換,使得右子樹的一個黑色爲左右共享,左子樹不再缺少<span style="white-space:pre"> </span>黑色,結束循環即可
q->color = 'B';
r->rchild->color = 'B';
left_rotate(q);
p = root;
}
}
else // if代碼的鏡像
{
r = q->lchild;
if(!r)
{
p = q;
continue;
}
if(r->color == 'R')
{
r->color = 'B';
q->color = 'R';
right_rotate(q);
r = q->lchild;
}
if((!r->lchild || r->lchild->color == 'B') && (!r->rchild || r->rchild->color == 'B'))
{
r->color = 'R';
p = q;
}
else
{
if(!r->lchild || r->lchild->color == 'B')
{
r->color = 'R';
r->rchild->color = 'B';
r = left_rotate(r);
}
r->color = q->color;
q->color = 'B';
r->lchild->color = 'B';
right_rotate(q);
p = root;
}
}
}
p->color = 'B'; // 找到了可以彌補的節點,將其染成黑色
}
delete node; //刪除node即可
}
template <typename T>
bool RBTree<T>::find(const T& elem)
{
return find_del(elem) != 0;
}
template <typename T>
void RBTree<T>::clear()
{
clear_node(root);
root = 0;
}</span>
4、
樹的遍歷:
<span style="font-family:Courier New;">template <typename T>
class RBTreeOperator
{
public:
RBTreeOperator() : tree(0) {}
RBTreeOperator(RBTree<T>& t) : tree(&t){}
~RBTreeOperator(){}
void FirstOrderTree();
void InOrderTree();
void PostOrderTree();
void LevelOrderTree();
private:
void FTraverse(RBTNode<T> *node);
void ITraverse(RBTNode<T> *node);
void PTraverse(RBTNode<T> *node);
void LTraverse(RBTNode<T> *node);
private:
RBTree<T> *tree;
};</span>
<span style="font-family:Courier New;">// 以下爲成員函數的實現</span>
<span style="font-family:Courier New;">template <typename T>
void RBTreeOperator<T>::FTraverse(RBTNode<T> *node)
{
stack<RBTNode<T>*> s;
s.push(node);
if(!node)
{
return;
}
while(!s.empty())
{
node = s.top();
s.pop();
cout << node->data << "\t";
if(node->rchild)
{
s.push(node->rchild);
}
if(node->lchild)
{
s.push(node->lchild);
}
}
}
template <typename T>
void RBTreeOperator<T>::ITraverse(RBTNode<T> *node)
{
stack<RBTNode<T>*> s;
while(node)
{
s.push(node);
node = node->lchild;
}
while(!s.empty())
{
node = s.top();
cout << node->data << "\t";
s.pop();
RBTNode<T> *temp = node->rchild;
while(temp)
{
s.push(temp);
temp = temp->lchild;
}
}
}
template <typename T>
void RBTreeOperator<T>::PTraverse(RBTNode<T> *node)
{
stack<RBTNode<T>*> s;
RBTNode<T> *p(node), *q(0);
while(p)
{
s.push(p);
p = p->lchild;
}
while(!s.empty())
{
p = s.top();
if(p->rchild && q != p->rchild)
{
p = p->rchild;
while(p)
{
s.push(p);
p = p->lchild;
}
}
else
{
q = p;
cout << p->data << "\t";
s.pop();
}
}
}
template <typename T>
void RBTreeOperator<T>::LTraverse(RBTNode<T> *node)
{
queue<RBTNode<T>*> q;
if(!node)
{
return;
}
q.push(node);
while(!q.empty())
{
node = q.front();
if(node->lchild)
{
q.push(node->lchild);
}
if(node->rchild)
{
q.push(node->rchild);
}
cout << node->data << "\t";
q.pop();
}
}
template <typename T>
void RBTreeOperator<T>::FirstOrderTree()
{
FTraverse(tree->root);
cout << endl;
}
template <typename T>
void RBTreeOperator<T>::InOrderTree()
{
ITraverse(tree->root);
cout << endl;
}
template <typename T>
void RBTreeOperator<T>::PostOrderTree()
{
PTraverse(tree->root);
cout << endl;
}
template <typename T>
void RBTreeOperator<T>::LevelOrderTree()
{
LTraverse(tree->root);
cout << endl;
}</span>
5、測試:
<span style="font-family:Courier New;">int main(int argc, char** argv) {
RBTree<int> tree;
RBTreeOperator<int> op(tree);
const int N(10);
int p[N] = {2, 5, 3, 9, 7, 8, 6, 10, 1, 4};
for(int i = 0; i < N; ++i)
{
tree.insert(p[i]);
}
op.FirstOrderTree();
op.InOrderTree();
op.PostOrderTree();
op.LevelOrderTree();
for(int i = 0; i < N; ++i)
{
tree.erase(p[i]);
op.FirstOrderTree();
op.InOrderTree();
}
return 0;
}</span>
6、小結:
以上便是今天下午的勞動成果了。寫完代碼後感覺對紅黑樹的理解更深入一些了,更重要的是對節點旋轉的作用以及需要節點旋轉的場合有了更深的瞭解:通過旋轉可以使一個節點的左右兩顆子樹“互通有無”,彌補其中一棵子樹缺少的顏色,這是通過對另一棵子樹的某個節點的顏色進行共享實現的。另一收穫就是碼代碼的時候萬萬要小心,一個不細心導致的錯誤,將會讓你付出很大的代價去發現它!