红黑树总结

红黑树学习笔记

红黑树的5个性质

  • 每个结点要么是红的,要么是黑的。
  • 根结点是黑的。
  • 每个叶结点(叶结点即指树尾端NIL指针或NULL结点)是黑的。
  • 如果一个结点是红的,那么它的俩个儿子都是黑的。
  • 对于任一结点而言,其到叶结点树尾端NIL指针的每一条路径都包含相同数目的黑结点。

注意黑色的nil结点,对于红黑树的删除的理解很重要。

《红黑树总结》

红黑树的插入

插入一个初始为红色的节点,有以下3种情况。

1.空树,使其颜色转为黑,成为根。
2.父为黑,无须调整。
3.父为红,根据以下图片进行调整。

《红黑树总结》
流程图如下所示
《红黑树总结》
根据图片就可以写出代码了~~~

红黑树的删除

红黑树的删除有点难以理解。

如果删除一个节点,他有后继节点,我们就用它的后继节点(或者前继节点)转变成它的颜色顶替它的位置。
所以我们不用考虑删除的节点是什么颜色,而是应该考虑顶替它的后继节点的什么颜色。
因为是后继节点,所以最终删除的要么只有一个右孩子,要么就是叶子节点(有两个nil节点)。

基于以上的情况,如果删除的该节点是红色,那么直接删除就可以了。
如果是黑色,那么就有以下两种情况
1.删除的节点(5)只有一个红色的右孩子(对于用后继节点顶替来考虑),则将儿子-》黑色-》结束。
2.删除的节点(5)的儿子是黑色(包括nil节点),将以儿子为当前点,进行调整。**
下面只分析将删除的节点的儿子为当前点,并且是左儿子的情况(也就是删除的最终节点是父节点的左儿子的情况…好难说清楚…)
比如下面删除2节点,用5节点(2的后继)顶替,那么5才是认为的删除的节点。然后5就是5的父节点的左儿子,下面处理的就是这种情况。
《红黑树总结》
删除节点2后
《红黑树总结》
注意此时6一定有兄弟节点,不然就不是红黑树了!!
然后将6做为当前点,按下图进行操作即可~(编程时要加上是右儿子的情况)
《红黑树总结》

感觉删除那里很难理解~这是对之前算法复习时候笔记的整理,有点久了,可能记错了,请不要怪罪 = =

// RBTree.cpp : Defines the entry point for the console application.
//
/* 性质1. 节点是红色或黑色。 性质2. 根节点是黑色。 性质3 每个叶节点(NIL节点,空节点)是黑色的。 性质4 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点) 性质5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。 */
#include "stdafx.h"
#include <iostream>
#include <queue>
using namespace std;


struct Node
{
    int key;//结点的值
    char color;
    Node *left, *right, *parent;

    // Constructor

    Node(int key)
    {
        this->key = key;
        left = right = parent = NULL;
        color = 'R';
    }
};
static Node* Tnil = new Node(-1);

// Class to represent Red-Black Tree
class RBTree
{
public:
    Node *root;


protected:

    void rotateLeft(Node *&, Node *&);//左旋操作,传入根结点和旋转的结点,成为自己右孩子的左孩子
    void rotateRight(Node *&, Node *&); //右旋操作,传入根结点和旋转的结点,成为自己左孩子的右孩子
    void transplant(Node*&u, Node*&v);//v子树代替u子树
    Node* minimum(Node*);//某个子树的最小值
    Node* find(Node*root,int data);//某值
    void RBTInsertFixup(Node *&, Node *&);
    void RBTDeleteFixup(Node *&, Node *&);
    Node* RBTInsert(Node*&root, Node *z);
public:
    // Constructor

    RBTree() {
        root = Tnil; 
        Tnil->color = 'B';
    }
    void insert(const int &n);
    void deleteN(const int &n);
    void clear(Node *&);
    Node* RBTDelete(Node*&root, Node *z);//删除z结点
};

void RBTree::clear(Node*&d)
{
    //判断二叉树是否为空 
    if (d != Tnil)
    {
        //1.清空左子树 
        clear(d->left);
        //2.清空右子树 
        clear(d->right);
        //3.清空根节点 
    // cout << d->key << endl;
        delete d;
        d = NULL;
    }

    d = Tnil;

}

// 对违反红黑树的地方进行调整
void RBTree::RBTInsertFixup(Node *&root, Node *&x)
{
    Node *parent_x = Tnil;
    Node *grand_parent_x = Tnil;

    while ((x != root) && (x->parent->color == 'R') && (x->color != 'B'))//当x的父结点为红色时,才需要调整,循环到当前点的父结点为黑色为至
    {

        parent_x = x->parent;//当前点的父节点
        grand_parent_x = x->parent->parent;//当前点的祖父节点

                                           //父为祖父左孩子
        if (parent_x == grand_parent_x->left)
        {
            Node *uncle_x = grand_parent_x->right;//叔结点
            if (uncle_x != Tnil &&uncle_x->color == 'R')//叔结点为红色
            {
                parent_x->color = 'B';
                uncle_x->color = 'B';
                grand_parent_x->color = 'R';
                x = grand_parent_x;
            }
            else//叔节点为黑色
            {
                if (x == parent_x->right)
                {
                    x = parent_x;
                    rotateLeft(root, x);
                }


                x->parent->color = 'B';
                x->parent->parent->color = 'R';

                rotateRight(root, grand_parent_x);
                x = x->parent;

            }
        }
        else//父为祖父右孩子
        {
            Node *uncle_x = grand_parent_x->left;//叔结点
            if (uncle_x != Tnil &&uncle_x->color == 'R')//叔结点为红色
            {
                parent_x->color = 'B';
                uncle_x->color = 'B';
                grand_parent_x->color = 'R';
                x = grand_parent_x;
            }
            else//叔节点为黑色
            {
                if (x == parent_x->left)
                {
                    x = parent_x;
                    rotateRight(root, x);
                }

                x->parent->color = 'B';
                x->parent->parent->color = 'R';

                rotateLeft(root, grand_parent_x);
                x = x->parent;

            }
        }
    }
    root->color = 'B';
}

void RBTree::RBTDeleteFixup(Node *&root, Node *&x)

{
    Node* sibling = Tnil;
    while (x != root&&x->color == 'B')
    {
        if (x==x->parent->left)//x是其父亲的左孩子
        {
            sibling = x->parent->right;
            if (sibling->color=='R')//第一种情况,兄弟颜色为红
            {
                sibling->color = 'B';
                x->parent->color = 'R';
                rotateLeft(root, x->parent);
                sibling = x->parent->right;//兄弟节点变了
            }
            else//兄弟颜色为黑
            {
                if (sibling->left->color=='B'&&sibling->right->color=='B')//情况二,兄弟的两个孩子都为黑色
                {
                    sibling->color = 'R';
                    x = x->parent;
                }
                else
                {
                    if (sibling->right->color=='B')//情况三,兄弟右子为黑,左子为红
                    {
                        sibling->color = 'R';
                        sibling->left->color = 'B';
                        rotateRight(root, sibling);
                        sibling = x->parent->right;//兄弟又变了
                    }
                    sibling->color = x->parent->color;//情况四,兄弟右子为红,左子颜色任意。
                    x->parent->color = 'B';
                    sibling->right->color = 'B';
                    rotateLeft(root, x->parent);
                    x = root;//结束
                }
            }
        }
        else//x是其父亲的右孩子
        {
            sibling = x->parent->left;
            if (sibling->color == 'R')//第一种情况,兄弟颜色为红
            {
                sibling->color = 'B';
                x->parent->color = 'R';
                rotateRight(root, x->parent);
                sibling = x->parent->left;//兄弟节点变了
            }
            else//兄弟颜色为黑
            {
                if (sibling->left->color == 'B'&&sibling->right->color == 'B')//情况二,兄弟的两个孩子都为黑色
                {
                    sibling->color = 'R';
                    x = x->parent;
                }
                else
                {
                    if (sibling->left->color =='B')//情况三,兄弟左子为黑,右子为红
                    {
                        sibling->color = 'R';
                        sibling->right->color = 'B';
                        rotateLeft(root, sibling);
                        sibling = x->parent->left;//兄弟又变了
                    }
                    sibling->color = x->parent->color;//情况四,兄弟左子为红,右子颜色任意。
                    x->parent->color = 'B';
                    sibling->left->color = 'B';
                    rotateRight(root, x->parent);
                    x = root;//结束
                }
            }
        }

    }
    x->color = 'B';
}

/* 像普通二叉树一样插入,返回根结点*/
Node* RBTree::RBTInsert(Node* &root, Node *z)
{
    Node*y = Tnil;//记录当前x的父结点
    Node*x = root;
    while (x != Tnil)
    {
        y = x;
        if (z->key < x->key)
            x = x->left;
        else
            x = x->right;
    }
    z->parent = y;
    if (y == Tnil)
    {
        z->color = 'B';
        root = z;
    }
    else if (z->key < y->key)
    {
        y->left = z;
    }
    else
    {
        y->right = z;
    }
    if (y->color=='R')
    RBTInsertFixup(root, z);
    return root;


}


//左旋操作,传入根结点和旋转的结点,成为自己右孩子的左孩子
void RBTree::rotateLeft(Node *&root, Node *&x)
{
    Node *y = x->right;//y是x的右孩子

    x->right = y->left;

    if (x->right != Tnil)//原来y没有左子树的就不需要改变y子树的父结点指向
        x->right->parent = x;

    y->parent = x->parent;//修改y的父结点

                          //x的父结点有以下三种情况
    if (x->parent == Tnil)//如果原来x是根结点,则y变成新的根结点
        root = y;

    else if (x == x->parent->left)//x原来是x父结点的左孩子
        x->parent->left = y;

    else
        x->parent->right = y;//x原来是x父结点的右孩子

    y->left = x;
    x->parent = y;
}

//右旋操作,传入根结点和旋转的结点,成为自己左孩子的右孩子
void RBTree::rotateRight(Node*&root, Node*&x)
{
    Node*y = x->left;
    x->left = y->right;
    if (y->right != Tnil)
        x->left->parent = x;
    y->parent = x->parent;
    if (x->parent == Tnil)
        root = y;
    else if (x == x->parent->left)
        x->parent->left = y;
    else
        x->parent->right = y;

    y->right = x;
    x->parent = y;

}


// Function to insert a new node with given key
void RBTree::insert(const int &key)
{
    Node *x = new Node(key);
    x->parent = x->left = x->right = Tnil;
    // Do a normal BST insert
    root = RBTInsert(root, x);

}
void RBTree::deleteN(const int &key)
{
    Node *x = find(root,key);
    if(x!=Tnil)
    // Do a normal BST insert
    root = RBTDelete(root, x);

}
//v子树代替u子树
void RBTree::transplant(Node*&u, Node*&v)
{
    if (u->parent == Tnil)//u为根节点
        root = v;
    else if (u == u->parent->left)//u为其父的左节点
        u->parent->left = v;
    else
        u->parent->right = v;
/* if (v != Tnil)*/
        v->parent = u->parent;
}

Node*RBTree::minimum(Node*x)//x子树的最小值
{
    while (x->left != Tnil)
    {
        x = x->left;
    }
    return x;
}
Node * RBTree::find(Node *root,int key)
{
    //int value = root->key;
    while (root->key!=key)
    {
        if (key > root->key)
            root = root->right;
        else
            root = root->left;

        if (root == Tnil)
        {
            cout << "树中没有 " << key << "这个值" << endl;
            return Tnil;
        }

    }
    return root;
}
Node* RBTree::RBTDelete(Node*&root, Node *z)//删除z结点
{
    Node*y = z;
    Node*x = Tnil;
    char y_original_color = y->color;
// if (z->left==Tnil&&z->right==Tnil)
// {
// if (z->parent->left == z)
// z->parent->left = Tnil;
// else
// z->parent->right = Tnil;
// return root;
// }
    if (z->left == Tnil)
    {
        x = z->right;
        transplant(z, x);

    }
    else if (z->right == Tnil)
    {
        x = z->left;
        transplant(z, x);
    }
    else
    {
        y = minimum(z->right);//y为z的后继
        y_original_color = y->color;
        x = y->right;
        if (y->parent == z)
            x->parent = y;
        else
        {

            transplant(y, y->right);
            y->right = z->right;
            y->right->parent = y;
        }
        transplant(z, y);
        y->left = z->left;
        y->left->parent = y;
        y->color = z->color;
    }
    if (y_original_color == 'B')
        RBTDeleteFixup(root, x);//x可能引起红黑树的性质被破坏
    return root;


}
/* 树形打印作用域 root:子树根 blk:缩进次数 */
void printTree(Node*root, int blk)
{

    if (root == Tnil)
        return;
    printTree(root->right, blk + 1);

    for (int i = 0; i < blk; i++)printf("| ");//缩进时输出"|"符号
                                              //for (int i = 0; i<blk; i++)printf(" ");//缩进
    printf("|—<%d %c>\n", root->key, root->color);//打印"|—<id>"形式


    printTree(root->left, blk + 1);


}


int main()
{
    //FILE *stream;

    //freopen_s(&stream,"D:\\xx.txt", "w", stdout);
    RBTree tree;
    int data,sum;
    cout << "请输入树的节点总数,输入0结束" << endl;
    while (scanf_s("%d", &sum) != EOF) {
        RBTree tree;
        if (sum == 0 )
            break;
        cout << "请输入节点数值" << endl;
        for (int i=0;i<sum; i++)
        {
            cin >> data;
            tree.insert(data);  
        }
        cout << "======================" << endl;
        printTree(tree.root, 0);
        cout << endl << "输入要删除的节点,输入-1表示结束" << endl;
        cin >> data;
        while (data!=-1)
        {
            tree.deleteN(data);
            cout << "删除" << data << "后:" << endl;
            cout << "======================" << endl;
            printTree(tree.root, 0);
            cout << endl << "输入要删除的节点,输入-1表示结束" << endl;
            cin >> data;
        }
        tree.clear(tree.root);
        printTree(tree.root, 0);
        cout << endl << "输入要删除的节点,输入-1表示结束" << endl;
        cout << "请输入树的节点总数,输入0结束" << endl;
    }
    return 0;
}

借鉴了几个博客(并偷了两张图片)和算法导论。没有记下博客。。。就不贴出来了。谢谢在网上分享的各位大神。

    原文作者:算法小白
    原文地址: https://blog.csdn.net/chen_xinjia/article/details/54630194
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞