红黑树总结

来源:互联网 发布:docker搭建java web 编辑:程序博客网 时间:2024/06/05 13:28

    • 红黑树学习笔记
      • 红黑树的5个性质
      • 红黑树的插入
      • 红黑树的删除

红黑树学习笔记

红黑树的5个性质

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

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

红黑树

红黑树的插入

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

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

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

红黑树的删除

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

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

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

0 0
原创粉丝点击