white Era 2021-08-10 18:05 采纳率: 0%
浏览 14
已结题

红黑树的插入删除等操作,代码写的很详细但是出现段错误,不知到错在哪


#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
//红黑树学习,主要难点,左旋,右旋,插入,删除
//红黑树主要是为了保证二叉搜索树的平衡,避免出现一条简单路径的深度高,一条简单路径深度低的情况
//红黑树的效率高,保证在最坏的情况下的时间复杂度的为O(lgn)
//红黑树的五条性质:
//1.每个节点或是红色的,或是黑色的
//2.根节点是黑色的
//3.每个叶节点(NIL)是黑色的
//4.如果一个节点是红色的,则它的两个子结点都是黑色的
//5.对每个结点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色结点
//*************************数据结构定义阶段*************************
typedef enum{RED,BLACK} Color;

typedef struct BST{
    int key;    //关键字
    Color color;//节点颜色
    struct BST *p,*left,*right; //双亲,左孩,右孩
    
    BST(){color = BLACK; p = left = right = NULL;}  //无参构造

}BSTNode;

typedef struct BST_Root{    //树根
    BSTNode *root;
    BSTNode *nil;   //红黑树是以一个标记结尾的

    BST_Root(){     //
        
        nil = new BSTNode();
        nil->color = BLACK; 
        nil->p = nil->left = nil->right = NULL;
        root = nil;
    }

}BSTRoot;
BSTRoot BT;  //这里我直接把树根先建好,后面方便使用nil

//*************************数据结构定义阶段*************************

//*************************查找*************************
//和一般的二叉搜索树一样的操作,只是结尾标志不再是NULL,而是统一的nil

BSTNode* tree_search(BSTNode *&T,int k){    //递归查找

    if(T != BT.nil && T->key != k){
        if(k < T->key)
            return tree_search(T->left,k);
        else
            return tree_search(T->right,k);
    }
    return T;
}

BSTNode* interative_tree_search(BSTNode *&T,int k){     //非递归查找
    BSTNode *t = T;

    while(t != BT.nil && t->key != k){
        if(k < t->key)
            t = t->left;
        else
            t = t->right;
    }
    return t;
}

//*************************查找*************************

//************************最大关键字查询,最小关键字查询,前驱和后继查询************************

BSTNode* tree_minmum(BSTNode *&T){  //最小关键字查询
    BSTNode *t = T;

    while(t!=BT.nil && t->left != BT.nil){
        t = t->left;
    }
    return t;
}

BSTNode* tree_maxmum(BSTNode *&T){  //最大关键字查询
    BSTNode *t = T;

    while(t!=BT.nil && t->right != BT.nil){
        t = t->right;
    }
    return t;
}

BSTNode* tree_successor(BSTNode *&T){   //后继查询,后继就是大于T.x的最小关键字节点
    BSTNode *t = T,*y = BT.nil;
    if(T == BT.nil) return T; 

    if(T->right != BT.nil)          //如果右子树不为空直接求右子树的最小节点
        return tree_minmum(T->right);
    
    y = t->p;

    while(y != BT.nil && y->right == t){
        t = y;
        y = y->p;
    }
    return y;
}

BSTNode* tree_predecessor(BSTNode *&T){ //前驱查询,前驱就是小于T.x的最大关键字节点
    BSTNode *t = T,*y = BT.nil;
    if(T == BT.nil) return T;

    if(T->left != BT.nil)          //如果左子树不为空直接求左子树的最大节点
        return tree_maxmum(T->left);
    
    y = t->p;

    while(y != BT.nil && y->left == t){ //这里就是没有左子树的情况,往上找,上面还有没有小于t.x的节点
        t = y;
        y = y->p;
    }
    return y;
}

//************************最大关键字查询,最小关键字查询,前驱和后继查询************************

//************************左旋和右旋************************

void left_rotate(BSTNode *&T,BSTNode *& x){

    BSTNode *y = x->right;  //x的右孩取出来
    x->right = y->left; //把y的左孩给x当右孩
    
    if(y->left != BT.nil){  //y的左孩不是nil就让它认x为爸
        y->left->p = x;
    }

    y->p = x->p;    

    if(x->p == BT.nil)  //如果x原来是根节点,那么更新根节点
        BT.root = y;
    else if(x == x->p->left)    //看x原来是它父节点的左孩还是右孩,因为从现在开始x不是它原来父节点的儿了,y才是
        x->p->left = y;
    else
        x->p->right = y;
    y->left = x;
    x->p = y;
    
}

void right_rotate(BSTNode *&T,BSTNode *&y){ //右旋,同上面是对称的
    
    BSTNode *x = y->left;
    
    y->left = x->right;
    
    if(x->right != BT.nil)
        x->right->p = y;
    
    x->p = y->p;

    if(y->p == BT.nil)
        BT.root = x;
    else if(y == y->p->left)
        y->p->left = x;
    else
        y->p->right = x;
    x->right = y;
    y->p = x;
}

//************************左旋和右旋************************

//************************插入************************

void RB_Insert_Fixup(BSTNode *&T,BSTNode *&z){
    //要判断父节点是红色才用调整,黑色直接插入
    while(z->p->color == RED){  
        //先确定父节点是祖父节点的左孩还是右孩
        if(z->p == z->p->p->left){  //这里是左孩
           BSTNode* y = z->p->p->right;     //找到祖父节点的右孩,就是叔节点
                                    
            if(y->color == RED){    //如果叔节点是红色的
            //第一种情况
                z->p->color = BLACK;    //那么把祖父的两个孩节点都变成黑色,然后祖父节点变成红色,z在移到祖父节点的位置
                y->color = BLACK;
                z->p->p->color = RED;
                z = z->p->p;
            } else if(z == z->p->right){    //说明叔节点是黑色的,并且z是它父节点的右孩,那么对z的父节点左旋
                //第二种情况
                z = z->p;               
                left_rotate(T,z);
            }else{
                //第三种情况    说明叔节点是黑色的,并且z是它父节点的左孩,那么对z的父节点右旋
                z->p->color = BLACK;        
                z->p->p->color = RED;
                right_rotate(T,z->p->p);
            }

        }else{  //这里是祖父节点的右孩,那么操作与上面对称

            BSTNode* y = z->p->p->left;

            if(y->color == RED){
                y->color = BLACK;
                z->p->color = BLACK;
                z->p->p->color = RED;
                z = z->p->p;
            }else if(z == z->p->left){
                
                z = z->p;
                right_rotate(T,z);
            }else{
                z->p->color = BLACK;
                z->p->p->color = RED;
                left_rotate(T,z->p->p);  
            }

        }
    }
    BT.root->color = BLACK;
}

void tree_insert(BSTNode *&T, int k){   //插入操作基本一样,就最后多了两步
    
    BSTNode *t = T,*y = BT.nil;

    BSTNode *z = new BSTNode();
    z->key = k;
    z->p = z->left = z->right = BT.nil;
    z->color = RED; //这里要把颜色设置为红色
    while(t!=BT.nil){
        
        y = t;

        if(k < t->key)
            t = t->left;
        else
            t = t->right;
    }

    z->p = y;

    if(y == BT.nil)
        BT.root = z;
    else if(k < y->key)
        y->left = z;
    else
        y->right = z;

    
    RB_Insert_Fixup(T,z);       //调整颜色,保持红黑性质
}

//************************插入************************


//************************删除************************

void tree_transplant(BSTNode *&T,BSTNode *&u,BSTNode *&v){  

    if(u->p == BT.nil)
        BT.root = v;
    else if(u == u->p->left)
        u->p->left = v;
    else
        u->p->right = v;
    v->p = u->p;
}

void RB_Delete_Fixup(BSTNode *&T,BSTNode *&x){

    while(x != T && x->color == BLACK){

        if(x == x->p->left){

            BSTNode *w = x->p->right;
            if(w->color == RED){
                w->color = BLACK;
                x->p->color = RED;
                left_rotate(T,x->p);
                w = x->p->right;
            }
            if(w->left->color == BLACK && w->right->color == BLACK){
                w->color = RED;
                x = x->p;
            }else if(w->right->color == BLACK){
                w->left->color = BLACK;
                w->color = RED;
                right_rotate(T,w);
                w = x->p->right;
            }
            w->color = x->p->color;
            x->p->color = BLACK;
            w->right->color = BLACK;
            left_rotate(T,x->p);
            x = T;
        }else{

            BSTNode *w = x->p->left;
            if(w->color == RED){
                w->color = BLACK;
                x->p->color = RED;
                right_rotate(T,x->p);
                w = x->p->left;
            }
            if(w->left->color == BLACK && w->right->color == BLACK){
                w->color = RED;
                x = x->p;
            }else if(w->right->color == BLACK){
                w->color = RED;
                w->right->color = BLACK;
                w = x->p->left;
            }
            w->color = w->p->color;
            x->p->color = BLACK;
            w->right->color = BLACK;
            right_rotate(T,x->p);
            x = T;
        }
    }
    x->color = BLACK;
}


void tree_delete(BSTNode *&T,BSTNode *&z){  //删除
    BSTNode *y = z,*x;
    Color y_color = y->color;

    if(z->left == BT.nil){  //左子树为空
        x = z->right;
        tree_transplant(T,z,z->right);
    }else if(z->right == BT.nil){   //右子树为空
        x = z->left;
        tree_transplant(T,z,z->left);
    }else{  //左右子树不为空

        y = tree_minmum(z->right);
        y_color = y->color;
        x = y->right;
        if(y->p == z)
            x->p = y;
        else {
            tree_transplant(T,y,y->right);
            y->right = z->right;
            y->right->p = y;
        }
        tree_transplant(T,z,y);
        y->left = z->left;
        y->left->p = y;
        y->color = z->color;
    }
    
    if(y_color == BLACK)
        RB_Delete_Fixup(T,x);
}

//************************删除************************

void inorder_input(BSTNode *&T){ //中序遍历输出
    if(T!=BT.nil){
        inorder_input(T->left);
        printf("%d ",T->key);
        inorder_input(T->right);
    }
}

int main(){

    int a[9] = {11,2,14,1,7,15,5,8,4};

    for(int i = 0;i<9;i++)
        tree_insert(BT.root,a[i]);

    printf("inorder input primitive sequence: ");
    inorder_input(BT.root);
    putchar('\n');
    printf("after digit 3 be deleted: ");
    BSTNode *z = tree_search(BT.root,7);
    tree_delete(BT.root, z);
    inorder_input(BT.root);
    putchar('\n');
    system("pause");
    return 0;
}

  • 写回答

0条回答 默认 最新

    报告相同问题?

    问题事件

    • 系统已结题 8月18日
    • 创建了问题 8月10日

    悬赏问题

    • ¥15 stm32开发clion时遇到的编译问题
    • ¥15 如何用Labview在myRIO上做LCD显示?(语言-开发语言)
    • ¥15 Vue3地图和异步函数使用
    • ¥15 C++ yoloV5改写遇到的问题
    • ¥20 win11修改中文用户名路径
    • ¥15 win2012磁盘空间不足,c盘正常,d盘无法写入
    • ¥15 用土力学知识进行土坡稳定性分析与挡土墙设计
    • ¥70 PlayWright在Java上连接CDP关联本地Chrome启动失败,貌似是Windows端口转发问题
    • ¥15 帮我写一个c++工程
    • ¥30 Eclipse官网打不开,官网首页进不去,显示无法访问此页面,求解决方法