紅黑樹的增加與刪除(完整源碼版)

/*
項目名稱:紅黑樹練習
實現功能:紅黑樹的增加和刪除
完成時間: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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章