紅-黑樹基本概念
紅-黑樹(Red-Black tree)是一種特殊的二叉查找樹,因此具有二叉查找樹的特徵:任意一個節點所包含的關鍵字,大於左孩子的關鍵字,小於右孩子的關鍵字。樹中每一個節點的顏色或者是黑色或者是紅色,和AVL樹一樣具有平衡性。每一個空指針用一個外部結點來替代,紅-黑樹的性質可以描述爲:
RB1:根節點和外部節點都是黑色。
RB2:在根至外部節點路徑上,沒有連續兩個節點是紅色。
RB3:在所有根至外部節點的路徑上,黑色節點的數目都相同。
還有一種描述,其取決於父子指針的顏色,由父節點指向紅色孩子的指針顏色爲紅,由父節點指向黑色兒子的指針顏色爲黑。所以上述性質可以等價描述爲:
RB1’:從內部節點指向外部節點的指針是黑色的。
RB2’:在跟至外部節點路徑上,沒有連續兩個指針式紅色的。
RB3’:在所有根至外部節點的路徑上,黑色指針的數目都相同。
紅-黑樹示意圖如下:
紅-黑樹的C++實現
對於節點顏色和指針顏色的性質描述,我們以下的討論只針對節點顏色,相應的指針的顏色變化很容易推斷出來。
1、紅-黑樹的節點
#pragma once
enum RBTreeColor{RED,BLACK};
template <typename T>
struct RBTreeNode
{
RBTreeColor color;
T key;
RBTreeNode<T>* leftChild;
RBTreeNode<T>* rightChild;
RBTreeNode<T>* parent;
RBTreeNode(T key, RBTreeColor c, RBTreeNode<T>* l,
RBTreeNode<T>* r, RBTreeNode<T>* p) :
key(value), color(c), leftChild(l), rightChild(r), parent(p) { }
RBTreeNode(T key, RBTreeColor c) : key(key), color(c),
leftChild(nullptr), rightChild(nullptr), parent(nullptr) { }
};
數據成員說明:
color:節點的顏色
key:關鍵字
leftChild:節點的左孩子
rightChild:節點的右孩子
parent:節點的父親
使用enum定義了一個枚舉類型對象,節點要麼是黑色,要麼是紅色。
2、紅-黑樹類的接口
//***RBTree.h
#pragma once
#include<iostream>
#include"RBTreeNode.h"
using namespace std;
template <typename T>
class RBTree
{
public:
RBTree() : root(nullptr) { }
~RBTree() { destroy(root); }
// 前序、中序、後序遍歷紅-黑樹
void preOrder() { preOrder(root); }
void inOrder() { inOrder(root); }
void postOrder() { postOrder(root); }
RBTreeNode<T>* find(const T& theKey) const;
// 查找最小和最大結點:返回結點的關鍵字指針。
T* minimum();
T* maximum();
// 將結點(theKey爲節點關鍵字)插入到紅黑樹中
void insert(const T& theKey);
// 刪除結點(theKey爲節點關鍵字)
void erase(const T& theKey);
// 銷燬紅黑樹
void destroy();
void output() { inOrder(root); cout << endl; }
private:
RBTreeNode<T>* root;
// 前序、中序、後序遍歷紅-黑樹
void preOrder(RBTreeNode<T>* theRoot) const;
void inOrder(RBTreeNode<T>* theRoot) const;
void postOrder(RBTreeNode<T>* theRoot) const;
// 查找最小結點:返回以theRoot爲根結點的紅-黑樹的最小結點
RBTreeNode<T>* minimum(RBTreeNode<T>* theRoot);
// 查找最大結點:返回以theRoot爲根結點的紅-黑樹的最大結點
RBTreeNode<T>* maximum(RBTreeNode<T>* theRoot);
// 左旋
void rightRotate(RBTreeNode<T>* gu);
// 右旋
void leftRotate(RBTreeNode<T>* gu);
// 插入修正函數
void insertFixUp(RBTreeNode<T>* u);
// 刪除修正函數
void eraseFixUp(RBTreeNode<T> *y, RBTreeNode<T> *py);
// 銷燬紅黑樹
void destroy(RBTreeNode<T>* &theRoot);
};
對於插入和刪除操作,首先和二叉查找樹一樣進行插入和刪除操作,若造成紅-黑樹不平衡,再用insertFixUp()和eraseFixUp()進行修正。
3、旋轉操作
當紅-黑樹失去平衡時,需要進行顏色變化和選擇操作,類似於AVL的旋轉,分爲左旋和右旋兩種:
leftRotate:
/*********************************
***leftRotate:
* gu pu
* / \ / \
* guL pu ----> gu puR
* / \ / \
* puL puR guL puL
**********************************/
template <typename T>
void RBTree<T>::leftRotate(RBTreeNode<T>* gu)
{
RBTreeNode<T>* pu = gu->rightChild;
gu->rightChild = pu->leftChild;
if (pu->leftChild != nullptr)
pu->leftChild->parent = gu;
pu->parent = gu->parent;
if (gu == root)
root = gu;
else
{
if (gu == gu->parent->leftChild)
gu->parent->leftChild = pu;
else
gu->parent->rightChild = pu;
}
pu->leftChild = gu;
gu->parent = pu;
}
rightRotate:
/*********************************
***rightRotate:
* gu pu
* / \ / \
* pu guR ----> puL gu
* / \ / \
* puL puR puR guR
**********************************/
template <typename T>
void RBTree<T>::rightRotate(RBTreeNode<T>* gu)
{
RBTreeNode<T>* pu = gu->leftChild;
gu->leftChild = pu->rightChild;
if (pu->rightChild != nullptr)
pu->rightChild->parent = gu;
pu->parent = gu->parent;
if (gu == root)
root = pu;
else
{
if (gu == gu->parent->leftChild)
gu->parent->leftChild = pu;
else
gu->parent->rightChild = pu;
}
pu->rightChild = gu;
gu->parent = pu;
}
4、插入
將一個節點插入到紅-黑樹中,和二叉查找樹一樣,但是因爲節點是有顏色的,所以可能導致樹失去平衡。如果插入的是“黑色”節點,將一定違反RB3(根到外部節點的黑色節點數目不等),而如果插入的是“紅色”節點,有可能違反RB2(連續兩個紅色節點),也有可能不違反。所以,我們將新插入的節點染成“紅色”,按照二叉查找樹的方法插入到紅-黑樹中,若失去平衡,再進行修正。
插入:
template <typename T>
void RBTree<T>::insert(const T& theKey)
{
//創建新節點,並着色爲“紅色”
RBTreeNode<T>* newNode =
new RBTreeNode<T>(theKey, RED);
if (newNode == nullptr)
return;
RBTreeNode<T>* p = root,
*pp = nullptr;
while (p != nullptr)
{
pp = p;
if (theKey < p->key)
p = p->leftChild;
else if (theKey > p->key)
p = p->rightChild;
else
{
cerr << "不允許添加相同的節點!" << endl;
return;
}
}
newNode->parent = pp;
if (pp != nullptr)
{
if (theKey < pp->key)
pp->leftChild = newNode;
else
pp->rightChild = newNode;
}
else
root = newNode;
//修正添加newNode造成的紅-黑樹失去平衡
insertFixUp(newNode);
}
不平衡的類型可以通過檢查新節點u、其父節點pu及其祖父節點gu來確定。RB2性質被破壞時,即連續兩個紅色節點:一個是u,另一個必定是它的父節點pu,因此pu存在。根據u的叔叔節點的顏色和父節點的位置,可以分爲六種情況:
a、父節點是左孩子,叔叔節點是紅色, 對應LLr或LRr,只需要進行顏色變化。將pu和guR變成“黑色”,gu變成“紅色”。若gu的父節點存在且爲“紅色”,將轉變成a、b、c、d、e或f情況,繼續迭代。
代碼:
if (guR && guR->color == RED)
{
pu->color = BLACK;
guR->color = BLACK;
gu->color = RED;
u = gu; //gu變成紅色,可能gu的父節點也爲紅色,使得程序繼續向上修正
continue;
}
b、父節點是左孩子,叔叔節點是黑色,u爲右孩子,對應LRb情況。進行一次左旋操作既可轉變成 c 情況。
代碼:
if (u == pu->rightChild)
{
leftRotate(pu);
swap(pu, u); //爲了接下來的右旋
}
c、父節點是左孩子,叔叔節點是黑色,u爲左孩子,對應LLb情況。進行右旋操作,並將pu置爲“黑色”,gu置爲“紅色”,即可恢復平衡。
代碼:
gu->color = RED;
pu->color = BLACK;
rightRotate(gu);
d、父節點是右孩子,叔叔節點是“紅色”,對應RRr或RLr,只需要進行顏色變化。將pu和guL變成“黑色”,gu變成“紅色”。若gu的父節點存在且爲“紅色”,將轉變成a、b、c、d、e或f情況,繼續迭代。
代碼:
if (guL && guL->color == RED)
{//RRr或RLr
pu->color = BLACK;
guL->color = BLACK;
gu->color = RED;
u = gu; //gu變成紅色,可能gu的父節點也爲紅色,使得程序繼續向上修正
continue;
}
e、父節點是右孩子,叔叔節點是黑色,u爲左孩子,對應RLb情況。進行一次右旋操作既可轉變成 f 情況。
代碼:
if (u == pu->leftChild)
{
rightRotate(pu);
swap(pu, u); //爲了接下來的左旋
}
f、父節點是右孩子,叔叔節點是黑色,u爲右孩子,對應RRb情況。進行左旋操作,並將pu置爲“黑色”,gu置爲“紅色”,即可恢復平衡。
代碼:
gu->color = RED;
pu->color = BLACK;
leftRotate(gu);
插入之後的修正代碼:
template <typename T>
void RBTree<T>::insertFixUp(RBTreeNode<T>* u)
{
RBTreeNode<T>* pu, *gu; //父節點,祖父節點
while ((pu = u->parent) && pu->color == RED)
{// 若“父節點存在,並且父節點的顏色是"紅色"
gu = pu->parent;
//pu是gu的左孩子
if (pu == gu->leftChild)
{
RBTreeNode<T>* guR = gu->rightChild; //guR是u的叔叔節點,gu的右孩子
//Case1: 叔叔節點爲紅色; 對應LLr或LRr情況,只需要進行顏色變化
if (guR && guR->color == RED)
{
pu->color = BLACK;
guR->color = BLACK;
gu->color = RED;
u = gu; //gu變成紅色,可能gu的父節點也爲紅色,使得程序繼續向上修正
continue;
}
//叔叔爲黑色,對應LLb和LRb情況
if (!guR || guR->color == BLACK)
{
//Case2: 叔叔爲黑色,u是pu的右孩子
if (u == pu->rightChild)
{//左旋加右旋
leftRotate(pu);
swap(pu, u); //爲了接下來的右旋
}
//Case3: 叔叔爲黑色,u是pu的左孩子
gu->color = RED;
pu->color = BLACK;
rightRotate(gu);
}
}
//pu是gu的右孩子
else
{
RBTreeNode<T>* guL = gu->leftChild; //guL是u的叔叔節點,gu的左孩子
//Case1: 叔叔節點爲紅色; 對應RRr或RLr情況,只需要進行顏色變化
if (guL && guL->color == RED)
{//RRr或RLr
pu->color = BLACK;
guL->color = BLACK;
gu->color = RED;
u = gu; //gu變成紅色,可能gu的父節點也爲紅色,使得程序繼續向上修正
continue;
}
//叔叔爲黑色,對應RRb和RLb情況
if (guL && guL->color == BLACK)
{
//Case2: 叔叔爲黑色,u是pu的左孩子; RLb
if (u == pu->leftChild)
{//右旋加左旋
rightRotate(pu);
swap(pu, u); //爲了接下來的左旋
}
//Case3: 叔叔爲黑色,u是pu的右孩子; RRb
gu->color = RED;
pu->color = BLACK;
leftRotate(gu);
}
}
}
root->color = BLACK;
}
5、刪除
首先找到要刪除的節點,類似於對二叉查找樹的刪除操作,對紅-黑樹的節點進行刪除,若刪除的節點是“紅色”,不會導致失去平衡,若刪除的節點是“黑色”,則一定違反違反的是RB3(根到外部節點的數目減少)。
刪除:
template <typename T>
void RBTree<T>::erase(const T& theKey)
{
RBTreeNode<T>* theNode = find(theKey);
if (theNode == nullptr)
return;
RBTreeColor color;
//當deleteNode有兩個孩子
if (theNode->leftChild != nullptr &&
theNode->rightChild != nullptr)
{
//找到左子樹最大節點替換待刪除節點
RBTreeNode<T>* max = maximum(theNode->leftChild);
color = max->color;
theNode->key = max->key;
RBTreeNode<T>* max_child = max->leftChild; //只可能是有左孩子
if (max_child != nullptr)
max_child->parent = max->parent;
max->parent->leftChild = max_child;
if (color == BLACK)
eraseFixUp(theNode, theNode->parent);
delete max;
max == nullptr;
return;
}
//待刪除節點最多隻有一個孩子
RBTreeNode<T>* c; //c存下替換的節點
if (theNode->leftChild != nullptr)
c = theNode->leftChild;
else
c = theNode->rightChild;
color = theNode->color;
if (theNode != root)
{
if (theNode == theNode->parent->leftChild)
theNode->parent->leftChild = c;
else
theNode->parent->rightChild = c;
}
else
root = c;
if (c)
c->parent = theNode->parent;
if (color == BLACK)
eraseFixUp(c, theNode->parent);
delete theNode;
theNode = nullptr;
}
只有刪除的節點爲“黑色”時,纔有可能造成不平衡。y是刪除之後替代的節點,所以y爲黑色,v是其兄弟節點,py是他們的父節點。y節點的階(當前節點到一外部節點的路徑上黑色節點的數目)比v節點的階小1。根據v的顏色和v的孩子的顏色可以分爲四種情況:
在進行刪除時,主要有下面幾種情形:
(1) y的兄弟爲紅色;
(2) y的兄弟節點w爲黑色,且v節點的兩個孩子都是黑色;
(3) y的兄弟節點w爲黑色,且v的左孩子是紅色,右孩子爲黑色;
(4) y的兄弟節點w爲黑色,且v的右孩子爲黑色.
Case1:v是“紅色”,必然py是黑色的,v的兩個孩子是黑色的。將py置爲“紅色”,v置爲“黑色”,對py進行左旋。更新v,將轉變成2、3或4的情況。
代碼:
if (v->color == RED)
{
py->color = RED;
v->color = BLACK;
leftRotate(py);
v = py->rightChild;
}
Case2:v是“黑色”,則py可能爲黑也可能爲紅,v的左右孩子均爲”黑色“。將v置爲”紅色“,即可使得y和v的階相同,但是否恢復平衡取決於py和py的父節點的顏色,更新py爲y,即可轉變成1、2、3或4情況,繼續迭代。
代碼:
if ((!v->leftChild || v->leftChild->color == BLACK) &&
(!v->rightChild || v->rightChild->color == BLACK))
{
v->color = RED;
y = py;
py = py->parent;
}
Case3:v是“黑色”,則py可能爲黑也可能爲紅,v的左孩子爲”紅色“,右孩子爲”黑色“。將v置爲”紅色“,v的左孩子置爲”黑色“,再對v進行右旋變化,更新v即可轉變成4情況。
代碼:
if (!y->rightChild || v->rightChild->color == BLACK)
{
v->color = RED;
if (v->leftChild)
v->leftChild->color = BLACK;
rightRotate(v);
y = py->rightChild;
}
Case4:v是”黑色“,則py可能爲黑也可能爲紅,v的右孩子爲”紅色“,左孩子任意顏色。將v置爲py的顏色,py置爲”黑色“,再對py進行左旋變化,即可恢復平衡。
代碼:
v->color = py->color;
if (v->rightChild)
v->rightChild->color = BLACK;
py->color = BLACK;
leftRotate(py);
y = root;
break;
刪除之後的修正代碼:
template <typename T>
void RBTree<T>::eraseFixUp(RBTreeNode<T>* y, RBTreeNode<T>* py)
{
RBTreeNode<T>* v; //y的兄弟節點
while ((!y || y->color == BLACK) && y != root)
{
//刪除節點在父節點py的左子樹
if (y == py->leftChild)
{
v = py->rightChild;
// Case 1: y的兄弟v是紅色的
if (v->color == RED)
{
py->color = RED;
v->color = BLACK;
leftRotate(py);
v = py->rightChild;
}
// Case 2: y的兄弟v是黑色,且v的倆個孩子也都是黑色的
if ((!v->leftChild || v->leftChild->color == BLACK) &&
(!v->rightChild || v->rightChild->color == BLACK))
{
v->color = RED;
y = py;
py = py->parent;
}
else
{
// Case 3: y的兄弟v是黑色的,並且v的左孩子是紅色,右孩子爲黑色
if (!y->rightChild || v->rightChild->color == BLACK)
{
v->color = RED;
if (v->leftChild)
v->leftChild->color = BLACK;
rightRotate(v);
y = py->rightChild;
}
// Case 4: y的兄弟v是黑色的;並且v的右孩子是紅色的,左孩子任意顏色
v->color = py->color;
if (v->rightChild)
v->rightChild->color = BLACK;
py->color = BLACK;
leftRotate(py);
y = root;
break;
}
}
//刪除節點在父節點py的右子樹
else
{
v = py->rightChild;
// Case 1: y的兄弟v是紅色的
if (v->color == RED)
{
py->color = RED;
v->color = BLACK;
rightRotate(py);
v = py->leftChild;
}
// Case 2: y的兄弟v是黑色,且v的倆個孩子也都是黑色的
if ((!v->leftChild || v->leftChild->color == BLACK) &&
(!v->rightChild || v->rightChild->color == BLACK))
{
v->color = RED;
y = py;
py = py->parent;
}
else
{
// Case 3: y的兄弟v是黑色的,並且v的左孩子是紅色,右孩子爲黑色
if (!y->leftChild || v->leftChild->color == BLACK)
{
v->color = RED;
if (v->rightChild)
v->rightChild->color = BLACK;
leftRotate(v);
y = py->leftChild;
}
// Case 4: y的兄弟v是黑色的;並且v的右孩子是紅色的,左孩子任意顏色
v->color = py->color;
if (v->leftChild)
v->leftChild->color = BLACK;
py->color = BLACK;
rightRotate(py);
y = root;
break;
}
}
}
if (y)
y->color = BLACK;
}
完整源碼
#pragma once
#include<iostream>
#include"RBTreeNode.h"
using namespace std;
template <typename T>
class RBTree
{
public:
RBTree() : root(nullptr) { }
~RBTree() { destroy(root); }
// 前序、中序、後序遍歷紅-黑樹
void preOrder() { preOrder(root); }
void inOrder() { inOrder(root); }
void postOrder() { postOrder(root); }
RBTreeNode<T>* find(const T& theKey) const;
// 查找最小和最大結點:返回結點的關鍵字指針。
T* minimum();
T* maximum();
// 將結點(theKey爲節點關鍵字)插入到紅黑樹中
void insert(const T& theKey);
// 刪除結點(theKey爲節點關鍵字)
void erase(const T& theKey);
// 銷燬紅黑樹
void destroy();
void output() { inOrder(root); cout << endl; }
private:
RBTreeNode<T>* root;
// 前序、中序、後序遍歷紅-黑樹
void preOrder(RBTreeNode<T>* theRoot) const;
void inOrder(RBTreeNode<T>* theRoot) const;
void postOrder(RBTreeNode<T>* theRoot) const;
// 查找最小結點:返回以theRoot爲根結點的紅-黑樹的最小結點
RBTreeNode<T>* minimum(RBTreeNode<T>* theRoot);
// 查找最大結點:返回以theRoot爲根結點的紅-黑樹的最大結點
RBTreeNode<T>* maximum(RBTreeNode<T>* theRoot);
// 左旋
void rightRotate(RBTreeNode<T>* gu);
// 右旋
void leftRotate(RBTreeNode<T>* gu);
// 插入修正函數
void insertFixUp(RBTreeNode<T>* u);
// 刪除修正函數
void eraseFixUp(RBTreeNode<T> *y, RBTreeNode<T> *py);
// 銷燬紅黑樹
void destroy(RBTreeNode<T>* &theRoot);
};
template <typename T>
void RBTree<T>::preOrder(RBTreeNode<T>* theRoot) const
{
if (theRoot != nullptr)
{
cout << theRoot->key << " ";
preOrder(theRoot->leftChild);
preOrder(theRoot->rightChild);
}
}
template <typename T>
void RBTree<T>::inOrder(RBTreeNode<T>* theRoot) const
{
if (theRoot != nullptr)
{
inOrder(theRoot->leftChild);
cout << theRoot->key << " ";
inOrder(theRoot->rightChild);
}
}
template <typename T>
void RBTree<T>::postOrder(RBTreeNode<T>* theRoot) const
{
if (theRoot != nullptr)
{
postOrder(theRoot->leftChild);
postOrder(theRoot->rightChild);
cout << theRoot->key << " ";
}
}
template <typename T>
RBTreeNode<T>* RBTree<T>::find(const T& theKey) const
{
RBTreeNode<T>* p = root;
while (p != nullptr)
{
if (theKey < p->key)
p = p->leftChild;
else if (theKey > p->key)
p = p->rightChild;
else
return p;
}
return nullptr;
}
template <typename T>
T* RBTree<T>::minimum()
{
RBTreeNode<T>* min = minimum(root);
if (min != nullptr)
return &min->key;
return nullptr;
}
template <typename T>
RBTreeNode<T>* RBTree<T>::minimum(RBTreeNode<T>* theRoot)
{
RBTreeNode<T>* p = theRoot,
*pp = nullptr;
while (p != nullptr)
{
pp = p;
p = p->leftChild;
}
return pp;
}
template <typename T>
T* RBTree<T>::maximum()
{
RBTreeNode<T>* max = maximum(root);
if (max != nullptr)
return &max->key;
return nullptr;
}
template <typename T>
RBTreeNode<T>* RBTree<T>::maximum(RBTreeNode<T>* theRoot)
{
RBTreeNode<T>* p = theRoot,
*pp = nullptr;
while (p != nullptr)
{
pp = p;
p = p->rightChild;
}
return pp;
}
/*********************************
***rightRotate:
* gu pu
* / \ / \
* pu guR ----> puL gu
* / \ / \
* puL puR puR guR
**********************************/
template <typename T>
void RBTree<T>::rightRotate(RBTreeNode<T>* gu)
{
RBTreeNode<T>* pu = gu->leftChild;
gu->leftChild = pu->rightChild;
if (pu->rightChild != nullptr)
pu->rightChild->parent = gu;
pu->parent = gu->parent;
if (gu == root)
root = pu;
else
{
if (gu == gu->parent->leftChild)
gu->parent->leftChild = pu;
else
gu->parent->rightChild = pu;
}
pu->rightChild = gu;
gu->parent = pu;
}
/*********************************
***leftRotate:
* gu pu
* / \ / \
* guL pu ----> gu puR
* / \ / \
* puL puR guL puL
**********************************/
template <typename T>
void RBTree<T>::leftRotate(RBTreeNode<T>* gu)
{
RBTreeNode<T>* pu = gu->rightChild;
gu->rightChild = pu->leftChild;
if (pu->leftChild != nullptr)
pu->leftChild->parent = gu;
pu->parent = gu->parent;
if (gu == root)
root = gu;
else
{
if (gu == gu->parent->leftChild)
gu->parent->leftChild = pu;
else
gu->parent->rightChild = pu;
}
pu->leftChild = gu;
gu->parent = pu;
}
template <typename T>
void RBTree<T>::insert(const T& theKey)
{
//創建新節點,並着色爲“紅色”
RBTreeNode<T>* newNode =
new RBTreeNode<T>(theKey, RED);
if (newNode == nullptr)
return;
RBTreeNode<T>* p = root,
*pp = nullptr;
while (p != nullptr)
{
pp = p;
if (theKey < p->key)
p = p->leftChild;
else if (theKey > p->key)
p = p->rightChild;
else
{
cerr << "不允許添加相同的節點!" << endl;
return;
}
}
newNode->parent = pp;
if (pp != nullptr)
{
if (theKey < pp->key)
pp->leftChild = newNode;
else
pp->rightChild = newNode;
}
else
root = newNode;
//修正添加newNode造成的紅-黑樹失去平衡
insertFixUp(newNode);
}
template <typename T>
void RBTree<T>::insertFixUp(RBTreeNode<T>* u)
{
RBTreeNode<T>* pu, *gu; //父節點,祖父節點
while ((pu = u->parent) && pu->color == RED)
{// 若“父節點存在,並且父節點的顏色是"紅色"
gu = pu->parent;
//pu是gu的左孩子
if (pu == gu->leftChild)
{
RBTreeNode<T>* guR = gu->rightChild; //guR是u的叔叔節點,gu的右孩子
//Case1: 叔叔節點爲紅色; 對應LLr或LRr情況,只需要進行顏色變化
if (guR && guR->color == RED)
{
pu->color = BLACK;
guR->color = BLACK;
gu->color = RED;
u = gu; //gu變成紅色,可能gu的父節點也爲紅色,使得程序繼續向上修正
continue;
}
//叔叔爲黑色,對應LLb和LRb情況
if (!guR || guR->color == BLACK)
{
//Case2: 叔叔爲黑色,u是pu的右孩子
if (u == pu->rightChild)
{//左旋加右旋
leftRotate(pu);
swap(pu, u); //爲了接下來的右旋
}
//Case3: 叔叔爲黑色,u是pu的左孩子
gu->color = RED;
pu->color = BLACK;
rightRotate(gu);
}
}
//pu是gu的右孩子
else
{
RBTreeNode<T>* guL = gu->leftChild; //guL是u的叔叔節點,gu的左孩子
//Case1: 叔叔節點爲紅色; 對應RRr或RLr情況,只需要進行顏色變化
if (guL && guL->color == RED)
{//RRr或RLr
pu->color = BLACK;
guL->color = BLACK;
gu->color = RED;
u = gu; //gu變成紅色,可能gu的父節點也爲紅色,使得程序繼續向上修正
continue;
}
//叔叔爲黑色,對應RRb和RLb情況
if (guL && guL->color == BLACK)
{
//Case2: 叔叔爲黑色,u是pu的左孩子; RLb
if (u == pu->leftChild)
{//右旋加左旋
rightRotate(pu);
swap(pu, u); //爲了接下來的左旋
}
//Case3: 叔叔爲黑色,u是pu的右孩子; RRb
gu->color = RED;
pu->color = BLACK;
leftRotate(gu);
}
}
}
root->color = BLACK;
}
template <typename T>
void RBTree<T>::erase(const T& theKey)
{
RBTreeNode<T>* theNode = find(theKey);
if (theNode == nullptr)
return;
RBTreeColor color;
//當deleteNode有兩個孩子
if (theNode->leftChild != nullptr &&
theNode->rightChild != nullptr)
{
//找到左子樹最大節點替換待刪除節點
RBTreeNode<T>* max = maximum(theNode->leftChild);
color = max->color;
theNode->key = max->key;
RBTreeNode<T>* max_child = max->leftChild; //只可能是有左孩子
if (max_child != nullptr)
max_child->parent = max->parent;
max->parent->leftChild = max_child;
if (color == BLACK)
eraseFixUp(theNode, theNode->parent);
delete max;
max == nullptr;
return;
}
//待刪除節點最多隻有一個孩子
RBTreeNode<T>* c; //c存下替換的節點
if (theNode->leftChild != nullptr)
c = theNode->leftChild;
else
c = theNode->rightChild;
color = theNode->color;
if (theNode != root)
{
if (theNode == theNode->parent->leftChild)
theNode->parent->leftChild = c;
else
theNode->parent->rightChild = c;
}
else
root = c;
if (c)
c->parent = theNode->parent;
if (color == BLACK)
eraseFixUp(c, theNode->parent);
delete theNode;
theNode = nullptr;
}
template <typename T>
void RBTree<T>::eraseFixUp(RBTreeNode<T>* y, RBTreeNode<T>* py)
{
RBTreeNode<T>* v; //y的兄弟節點
while ((!y || y->color == BLACK) && y != root)
{
//刪除節點在父節點py的左子樹
if (y == py->leftChild)
{
v = py->rightChild;
// Case 1: y的兄弟v是紅色的
if (v->color == RED)
{
py->color = RED;
v->color = BLACK;
leftRotate(py);
v = py->rightChild;
}
// Case 2: y的兄弟v是黑色,且v的倆個孩子也都是黑色的
if ((!v->leftChild || v->leftChild->color == BLACK) &&
(!v->rightChild || v->rightChild->color == BLACK))
{
v->color = RED;
y = py;
py = py->parent;
}
else
{
// Case 3: y的兄弟v是黑色的,並且v的左孩子是紅色,右孩子爲黑色
if (!y->rightChild || v->rightChild->color == BLACK)
{
v->color = RED;
if (v->leftChild)
v->leftChild->color = BLACK;
rightRotate(v);
y = py->rightChild;
}
// Case 4: y的兄弟v是黑色的;並且v的右孩子是紅色的,左孩子任意顏色
v->color = py->color;
if (v->rightChild)
v->rightChild->color = BLACK;
py->color = BLACK;
leftRotate(py);
y = root;
break;
}
}
//刪除節點在父節點py的右子樹
else
{
v = py->rightChild;
// Case 1: y的兄弟v是紅色的
if (v->color == RED)
{
py->color = RED;
v->color = BLACK;
rightRotate(py);
v = py->leftChild;
}
// Case 2: y的兄弟v是黑色,且v的倆個孩子也都是黑色的
if ((!v->leftChild || v->leftChild->color == BLACK) &&
(!v->rightChild || v->rightChild->color == BLACK))
{
v->color = RED;
y = py;
py = py->parent;
}
else
{
// Case 3: y的兄弟v是黑色的,並且v的左孩子是紅色,右孩子爲黑色
if (!y->leftChild || v->leftChild->color == BLACK)
{
v->color = RED;
if (v->rightChild)
v->rightChild->color = BLACK;
leftRotate(v);
y = py->leftChild;
}
// Case 4: y的兄弟v是黑色的;並且v的右孩子是紅色的,左孩子任意顏色
v->color = py->color;
if (v->leftChild)
v->leftChild->color = BLACK;
py->color = BLACK;
rightRotate(py);
y = root;
break;
}
}
}
if (y)
y->color = BLACK;
}
template <typename T>
void RBTree<T>::destroy()
{
destroy(root);
}
template <typename T>
void RBTree<T>::destroy(RBTreeNode<T>* &theRoot)
{
if (theRoot == nullptr)
return;
destroy(theRoot->leftChild);
destroy(theRoot->rightChild);
delete theRoot;
theRoot = nullptr;
}