/*
項目名稱:紅黑樹練習
實現功能:紅黑樹的增加和刪除
完成時間:2018年4月11日
編輯者:尹浩龍
*/
#include<iostream>
#include<ctime>
using namespace std;
//紅黑樹節點類
template<typename T>
class TreeNode{
public:
T NodeData;//節點的值
bool Color;//節點的顏色
TreeNode<T>* Letf;//左子樹
TreeNode<T>* Right;//右子樹
TreeNode<T>* TheLast;//指向父節點
TreeNode(T& NewNodeData);
TreeNode(T& NewNodeData, TreeNode<T>* Letf, TreeNode<T>* Right, TreeNode<T>* TheLast, bool Color);
};
template<typename T>TreeNode<T>::TreeNode(T& NewNodeData) : NodeData(NewNodeData){
Color = true;
Letf = Right = TheLast = NULL;
}
template<typename T>TreeNode<T>::TreeNode(T& NewNodeData, TreeNode<T>* Letf, TreeNode<T>* Right, TreeNode<T>* TheLast, bool Color) : NodeData(NewNodeData), Letf(Letf), Right(Right), TheLast(TheLast), Color(Color){
}
template<typename A, typename B>
class RedBlackTree{
public:
RedBlackTree();//構造函數
void AddNode(const A& Keyword, const B& Data);//增加節點
void DelNode(const A& Keyword);//刪除節點
void operator *();
private:
void AntiClockwise(TreeNode<pair<A, B>>* NewNode);//左旋方法
void Clockwise(TreeNode<pair<A, B>>* NewNode);//右旋方法
void AddRepairTree(TreeNode<pair<A, B>>* NewNode);//增加後修復樹 使樹恢復紅黑樹的特性
void DelRepairTree(TreeNode<pair<A, B>>* delNode, TreeNode<pair<A, B>>* Current);//刪除後修復樹 使樹恢復紅黑樹的特性
void SetRed(TreeNode<pair<A, B>>* NewNode);//設置節點爲紅色
void SetBlack(TreeNode<pair<A, B>>* NewNode);//設置節點爲黑色
bool IsRed(TreeNode<pair<A, B>>* NewNode);//設置節點爲紅色
void ShowRoot();//顯示根節點
void ShowSize();//顯示樹的節點數
void Echo();//打印樹
void PutTree(TreeNode<pair<A, B>>* NewNode);//遍歷樹
void PutNode(TreeNode<pair<A, B>>* NewNode);//打印節點
TreeNode<pair<A, B>>* Root;//根節點指針
int TreeSize;//樹的節點
int OutLength;//樹的節點
};
template<typename A, typename B>RedBlackTree<A, B>::RedBlackTree(){
Root = NULL;
TreeSize = 0;
OutLength = -1;
}
template<typename A, typename B> void RedBlackTree<A, B>::AddNode(const A& Keyword, const B& Data){
TreeNode<pair<A, B>>* Current = Root;
TreeNode<pair<A, B>>* Previous = NULL;
while (Current != NULL)
{
Previous = Current;
if (Keyword > Current->NodeData.first){
Current = Current->Right;
}
else if (Keyword < Current->NodeData.first){
Current = Current->Letf;
}
else{
Current->NodeData.second;
return;
}
}
TreeNode<pair<A, B>>* NewNodeData = new TreeNode<pair<A, B>>(pair<A, B>(Keyword, Data));
if (Previous == NULL){//樹爲空直接塗黑插入
NewNodeData->Color = false;
Root = NewNodeData;
}
else{
NewNodeData->TheLast = Previous;
if (Keyword > Previous->NodeData.first){
Previous->Right = NewNodeData;
}
else{
Previous->Letf = NewNodeData;
}
AddRepairTree(NewNodeData);
}
TreeSize++;
}
template<typename A, typename B> void RedBlackTree<A, B>::DelNode(const A& Keyword){
TreeNode<pair<A, B>>* Current = Root, *Father = NULL, *Leader = NULL, *Subordinate = NULL, *Alternate = NULL;
while (Current != NULL&&Current->NodeData.first != Keyword)
{
Father = Current;
if (Keyword > Current->NodeData.first){
Current = Current->Right;
}
else{
Current = Current->Letf;
}
}
if (Current == NULL){
cout << "指定的結點沒有找到,無法刪除" << endl;
return;
}
if (Current->Letf != NULL&&Current->Right != NULL){//有兩個孩子
Leader = Current;
Subordinate = Current->Letf;
while (Subordinate->Right != NULL)//找到替換的節點
{
Leader = Subordinate;
Subordinate = Subordinate->Right;
}
TreeNode<pair<A, B>>* Replace = new TreeNode<pair<A, B>>(Subordinate->NodeData, Current->Letf, Current->Right, Current->TheLast, Current->Color);//用替換節點的值 和刪除節點的顏色和關係生成新的節點
if (Father == NULL){//說明刪除的是跟節點
Root = Replace;
}
else if (Father->Letf == Current){
Father->Letf = Replace;
}
else if (Father->Right == Current){
Father->Right = Replace;
}
//處理要刪除的節點
if (Leader == Current){//如果直接用左子樹替換刪除節點
if (Subordinate->Letf != NULL){
Alternate = Subordinate->Letf;
Alternate->TheLast = Replace;
}
else{
Alternate = NULL;
}
Replace->Letf = Alternate;
}
else{//替換節點不是刪除節點的左子樹
if (Subordinate->Letf != NULL){
Alternate = Subordinate->Letf;
Alternate->TheLast = Leader;
}
else{
Alternate = NULL;
}
Leader->Right = Alternate;
}
DelRepairTree(Subordinate, Alternate);
delete Subordinate;
delete Current;
Father = Current = Leader = Subordinate = NULL;
}
else{//如果有一個子樹或者沒有子樹的情況
if (Father == NULL){//說明刪除的是跟節點 且只有一個子節點或者沒有子節點
if (Current->Letf != NULL){
Alternate = Current->Letf;
Alternate->TheLast = NULL;//根節點的上級指向空
}
else{
Alternate = Current->Right;
if (Alternate != NULL){
Alternate->TheLast = NULL;
}
}
Root = Alternate;
}
else{//刪除的不是根節點 且只有一個子節點或者沒有子節點
if (Current->Letf != NULL){//有一個左子樹
Alternate = Current->Letf;
if (Current == Father->Letf){
Father->Letf = Alternate;
}
else{
Father->Right = Alternate;
}
Alternate->TheLast = Father;//讓新連接上的節點指向正確的上級
}
else if (Current->Right != NULL){//有一個右子樹
Alternate = Current->Right;
if (Current == Father->Letf){
Father->Letf = Alternate;
}
else{
Father->Right = Alternate;
}
Alternate->TheLast = Father;//讓新連接上的節點指向正確的上級
}
else{//沒有子樹
if (Current == Father->Letf){
Father->Letf = NULL;
}
else{
Father->Right = NULL;
}
Alternate = NULL;
}
DelRepairTree(Current, Alternate);
}
delete Current;
Father = Current = NULL;
}
TreeSize--;
}
template<typename A, typename B> void RedBlackTree<A, B>::operator *(){
OutLength = -1;
cout << endl;
ShowSize();
ShowRoot();
Echo();
}
template<typename A, typename B> void RedBlackTree<A, B>::AntiClockwise(TreeNode<pair<A, B>>* NewNode){//左旋
/*
A <-傳進來爲A 轉換後: C
/ \ / \
B C A E
/ \ / \
D E B D
*/
if (NewNode != NULL) {
TreeNode<pair<A, B>>* Temp = NewNode->Right;//用一個指針指向C
//修改子樹所屬
NewNode->Right = Temp->Letf;//把C的左子樹變成A的右子樹
if (Temp->Letf != NULL){//如果D爲空,A的右子樹爲空,不需要再讓D連接A,如果D不爲空就把D的向上指針指向A
Temp->Letf->TheLast = NewNode;
}
//修改外聯節點
Temp->TheLast = NewNode->TheLast;//C的【向上指針】指向A的【向上指針】指向,爲C替代A做準備
if (NewNode->TheLast == NULL){//如果A的【向上指針】等於空說明A是紅黑樹的根節點
Root = Temp;//當A是根節點時需要把根節點移動到C 讓C成爲新的根節點
}
else if (NewNode->TheLast->Letf == NewNode)//A節點是上級節點的左子樹就讓C成爲A上級的左子樹
NewNode->TheLast->Letf = Temp;
else
NewNode->TheLast->Right = Temp;
Temp->Letf = NewNode;//讓A成爲C的左子樹
NewNode->TheLast = Temp;//連接A到C
}
}
template<typename A, typename B> void RedBlackTree<A, B>::Clockwise(TreeNode<pair<A, B>>* NewNode){//右旋
/*
A <-傳遞進來A 轉換後: B
/ \ / \
B C D A
/ \ / \
D E E C
*/
if (NewNode != NULL) {
TreeNode<pair<A, B>>* Temp = NewNode->Letf;//用一個指針指向B
//修改子樹所屬
if (Temp->Right != NULL){//如果E爲空,A的左子樹爲空,不需要再讓E連接A,如果E不爲空就把E的向上指針指向A
NewNode->Letf = Temp->Right;//把C的左子樹變成A的右子樹
Temp->Right->TheLast = NewNode;
}
else{
NewNode->Letf = NULL;
}
//修改外聯節點
Temp->TheLast = NewNode->TheLast;//B的【向上指針】指向A的【向上指針】指向,爲B替代A做準備
if (NewNode->TheLast == NULL){//如果A的【向上指針】等於空說明A是紅黑樹的根節點
Root = Temp;//當A是根節點時需要把根節點移動到C 讓C成爲新的根節點
Temp->Color = false;
}
else if (NewNode->TheLast->Letf == NewNode)//A節點是上級節點的左子樹就讓C成爲A上級的左子樹
NewNode->TheLast->Letf = Temp;
else
NewNode->TheLast->Right = Temp;
Temp->Right = NewNode;//讓A成爲C的右子樹
NewNode->TheLast = Temp;//連接A到C
}
}
template<typename A, typename B> void RedBlackTree<A, B>::AddRepairTree(TreeNode<pair<A, B>>* NewNode){
TreeNode<pair<A, B>>*Grandpa = NULL, *Pedar = NULL, *Uncle = NULL, *Temp = NULL;
while (NewNode->TheLast != NULL&&NewNode->TheLast->Color)//如果NewNNewNode->TheLast==NULL說明到達根節點或者父節點不是紅色不用繼續處理
{
Pedar = NewNode->TheLast;
Grandpa = Pedar->TheLast;
if (Pedar == Grandpa->Letf){//說明父親在爺爺的左側
Uncle = Grandpa->Right;//找到叔叔節點
if (Uncle != NULL&& Uncle->Color){//如果叔叔是紅色
SetBlack(Uncle);//把叔叔和父親都改爲黑色 爺爺改爲紅色
SetBlack(Pedar);
SetRed(Grandpa);
NewNode = Grandpa;
continue;
}
else{
if (NewNode == Pedar->Right){
//如果新節點在父親右側 父親在爺爺左側 就旋轉爲左側處理
//此處判斷不能寫成賦值 寫成賦值後程序不會報錯 根節點不會變化 紅黑樹就不成立了
AntiClockwise(Pedar);
NewNode = Pedar;
continue;
}
SetBlack(Pedar);
SetRed(Grandpa);
Clockwise(Grandpa);
NewNode = Pedar;
}
}
else{//父親在爺爺的右側
Uncle = Grandpa->Letf;//找到叔叔節點
if (Uncle != NULL&& Uncle->Color){//如果叔叔是紅色
SetBlack(Uncle);//把叔叔和父親都改爲黑色 爺爺改爲紅色
SetBlack(Pedar);
SetRed(Grandpa);
NewNode = Grandpa;
continue;
}
else{
if (NewNode == Pedar->Letf){
Clockwise(Pedar);
NewNode = Pedar;
continue;
}
SetBlack(Pedar);
SetRed(Grandpa);
AntiClockwise(Grandpa);
NewNode = Pedar;
}
}
}
SetBlack(Root);
}
template<typename A, typename B> void RedBlackTree<A, B>::DelRepairTree(TreeNode<pair<A, B>>* delNode, TreeNode<pair<A, B>>* Current){
TreeNode<pair<A, B>>* Pedar = NULL, *Brother = NULL;
if (!IsRed(delNode)){
Pedar = delNode->TheLast;
while (Current != Root && (Current == NULL || !IsRed(Current))){
if (Current == Pedar->Letf) {
Brother = Pedar->Right;
if (Brother != NULL&&IsRed(Brother)){
SetBlack(Brother);
SetRed(Pedar);
AntiClockwise(Pedar);
Brother = Pedar->Right;
}
if ((Brother->Letf == NULL || !IsRed(Brother->Letf)) && (Brother->Right == NULL || !IsRed(Brother->Right))){
//兄弟節點沒有子樹 或者子樹都爲黑的情況
SetRed(Brother);
Current = Pedar;
Pedar = Pedar->TheLast;
}
else{
if (Brother->Right == NULL || !IsRed(Brother->Right)){
if (Brother->Letf != NULL)SetBlack(Brother->Letf);
SetRed(Brother);
Clockwise(Brother);
Brother = Pedar->Right;
}
Brother->Color = Pedar->Color;
SetBlack(Current);
if (Brother->Right != NULL)SetBlack(Brother->Right);
AntiClockwise(Pedar);
break;
}
}
else { // same as above, with _M_right <-> _M_left.
Brother = Current->Letf;
if (IsRed(Brother)) {
SetBlack(Brother);
SetRed(Pedar);
Clockwise(Pedar);
Brother = Pedar->Letf;
}
if ((Brother->Right == NULL || !IsRed(Brother->Right)) && (Brother->Letf == NULL || !IsRed(Brother->Letf))){
SetRed(Brother);
Current = Pedar;
Pedar = Pedar->TheLast;
}
else {
if (Brother->Letf == NULL || !IsRed(Brother->Letf)){
if (Brother->Right != NULL)SetBlack(Brother->Right);
SetRed(Brother);
AntiClockwise(Brother);
Brother = Pedar->Letf;
}
Brother->Color = Pedar->Color;
SetBlack(Pedar);
if (Brother->Letf != NULL)SetBlack(Brother->Letf);
Clockwise(Pedar);
break;
}
}
}
SetBlack(Current);
}
}
template<typename A, typename B> void RedBlackTree<A, B>::SetRed(TreeNode<pair<A, B>>* NewNode){
NewNode->Color = true;
}
template<typename A, typename B> void RedBlackTree<A, B>::SetBlack(TreeNode<pair<A, B>>* NewNode){
NewNode->Color = false;
}
template<typename A, typename B> bool RedBlackTree<A, B>::IsRed(TreeNode<pair<A, B>>* NewNode){
return NewNode->Color;
}
template<typename A, typename B> void RedBlackTree<A, B>::ShowRoot(){
cout << "根節點是:"; PutNode(Root);
}
template<typename A, typename B> void RedBlackTree<A, B>::ShowSize(){
cout << "當前樹中有節點:" << TreeSize << "個。" << endl;
}
template<typename A, typename B> void RedBlackTree<A, B>::Echo(){
cout << "紅黑樹節點列表:" << endl;
PutTree(Root); cout << endl;
}
template<typename A, typename B> void RedBlackTree<A, B>::PutTree(TreeNode<pair<A, B>>* NewNode){
if (NewNode != NULL){
PutTree(NewNode->Letf);
PutNode(NewNode);
PutTree(NewNode->Right);
}
}
template<typename A, typename B> void RedBlackTree<A, B>::PutNode(TreeNode<pair<A, B>>* NewNode){
cout << "\t[" << NewNode->NodeData.first << "|" << NewNode->Color << "|" << NewNode->NodeData.second << "]";
OutLength++;
if (OutLength % 3 == 0){
cout << endl;
}
}
int main(){
srand((unsigned)time(NULL));
RedBlackTree<int, int> myTree;
for (int i = 1; i < 27; i++)
myTree.AddNode(i, rand() % 1000 + 1000);
*myTree;
myTree.DelNode(1);
*myTree;
myTree.DelNode(9);
*myTree;
system("pause");
return 0;
}
紅黑樹的增加與刪除(完整源碼版)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.