C++实现红黑树基本操作

 

#include <iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
#define RED 0  //红色用数字0表示
#define BLACK 1 //黑色用数字1表示
#define COLOR(x) ((x)->color)//获取x节点颜色
#define PARENTNODE(x) ((x)->parentNode)//获取x节点的父节点
#define SET_PARENT(x,p) ((x)->parentNode=(p)) //设置x节点的父节点
#define SET_COLOR(x,c) ((x)->color=(c))//设置x节点的颜色
#define SET_BLACK(x) ((x)->color=BLACK) //将x节点的颜色置为黑色
#define SET_RED(x) ((x)->color=RED) //将x节点的颜色置为红色
#define IS_BLACK(x) ((x)->color==BLACK)//判断x节点的颜色是否为黑色
#define IS_RED(x) ((x)->color==RED) //判断x节点的颜色是否为红色


typedef struct RBTNode
{

    int color;//红黑树的节点颜色
    int key;//红黑树节点的值
    struct RBTNode* parentNode;//父节点
    struct RBTNode* lChild;//左孩子
    struct RBTNode* rChild;//右孩子

} Node; //定义红黑树结点
typedef struct RBTree
{

    Node* root;//根节点
    int treeSize;//树的大小
} RBTree;
Node* createNode(int data);//创建红黑树节点
void leftRotation(RBTree* tree,Node* x);//将x节点左旋
void rightRotation(RBTree* tree,Node* y);//将y节点右旋
void traversePreorder(Node* root);//先序遍历红黑树
void traverseInorder(Node* root);//中序遍历红黑树

RBTree* createBbtree();//创建一棵红黑树
void adjustNode(RBTree* tree,Node* node);//调整结点
void insertRbtree(RBTree* tree,Node* node);//插入节点
Node* searchNode(Node* root,int key);//查找节点
void adjustDelete(RBTree* tree,Node* node,Node* parent); //调整删除节点
void deleteNode(RBTree* tree,Node* node);//删除节点
void deleteRbtree(RBTree* tree,int key);//根据已知数值删除节点



int main()
{
    int arr[9]= {10,40,30,60,90,70,20,50,80};
    int length=9;
    RBTree* tree=createBbtree();//创建一棵红黑树
    for(int i=0; i<length; i++)
    {
        insertRbtree(tree,createNode(arr[i]));//往红黑树中插入节点

    }
    printf("先序遍历结果如下:\n");
    traversePreorder(tree->root);//先序遍历红黑树
    printf("--------------------\n");
    printf("中序遍历的结果如下:\n");
    traverseInorder(tree->root);//中序遍历红黑树
    printf("--------------------\n");

    deleteRbtree(tree,80);//删除80


    printf("先序遍历结果如下:\n");
    traversePreorder(tree->root);//先序遍历红黑树
    printf("--------------------\n");
    printf("中序遍历的结果如下:\n");
    traverseInorder(tree->root);//中序遍历红黑树
    printf("--------------------\n");




    return 0;
}


Node* createNode(int data)//创建红黑树节点
{
    Node* newNode=new Node;
    newNode->color=BLACK;//把新节点的颜色置为黑色
    newNode->key=data;
    //初始化节点
    //将父节点和左右孩子节点均置为空
    newNode->parentNode=NULL;
    newNode->lChild=NULL;
    newNode->rChild=NULL;
    return newNode;//返回新创建的节点

}

void leftRotation(RBTree* tree,Node* x)//将x节点左旋
{
    Node* y=x->rChild;
    x->rChild=y->lChild;
    if(y->lChild!=NULL)
    {
        y->lChild->parentNode=x;

    }
    y->parentNode=x->parentNode;
    if(x->parentNode==NULL)//判断x节点是否为根节点
    {

        tree->root=y;
    }
    else if(x->parentNode->lChild==x)//判断x是否为左子树
    {
        x->parentNode->lChild=y;
    }
    else
    {
        x->parentNode->rChild=y;
    }
    y->lChild=x;
    x->parentNode=y;
}
void rightRotation(RBTree* tree,Node* y)//将y节点右旋
{
    Node* x=y->lChild;
    y->lChild=x->rChild;
    if(x->rChild!=NULL)
    {
        x->rChild->parentNode=y;
    }
    x->parentNode=y->parentNode;
    if(y->parentNode==NULL)//判断y节点是否为根节点
    {
        tree->root=x;
    }
    else if(y==y->parentNode->lChild)
    {
        y->parentNode->lChild=x;
    }
    else
    {
        y->parentNode->rChild=x;
    }
    x->rChild=y;
    y->parentNode=x;
}

void traversePreorder(Node* root)//先序遍历红黑树
{

    if(root!=NULL)//判断该树是否为空
    {
        //打印节点的值和颜色
        printf("%d---%s\n",root->key,root->color?"black":"red");
        traversePreorder(root->lChild);
        traversePreorder(root->rChild);
    }

}
void traverseInorder(Node* root)//中序遍历红黑树
{
    if(root!=NULL)
    {
        traverseInorder(root->lChild);
        printf("%d---%s\n",root->key,root->color?"black":"red");
        traverseInorder(root->rChild);
    }
}
RBTree* createBbtree()//创建一棵红黑树
{
    RBTree* tree=new RBTree;
    tree->root=NULL;//将树的根节点初始化为空
    tree->treeSize=0;//将树的大小初始化为0
    return tree;
}

void adjustNode(RBTree* tree,Node* node)//调整节点
{
    Node* parent,*Gparent;
    while((parent=PARENTNODE(node))&&IS_RED(parent))//判断父节点是否非空且颜色是否是红色
    {
        Gparent=PARENTNODE(parent);//获取祖父节点
        if(parent==Gparent->lChild)//父节点是祖父节点的左孩子
        {
            //情况一:叔叔节点是红色
            Node* uncle=Gparent->rChild;
            if(uncle && IS_RED(uncle))
            {
                SET_BLACK(uncle);//将叔叔节点设置为黑色
                SET_BLACK(parent);//将父节点设置为黑色
                SET_RED(Gparent);//将祖父节点设置为红色
                node=Gparent;
                continue;

            }
            //情况二:叔叔节点是黑色,当前节点是右孩子
            else if(parent->rChild==node)
            {
                leftRotation(tree,parent);
                Node* temp=parent;
                parent=node;
                node=temp;
            }
            else
            {
                //情况三:叔叔节点是黑色,当前节点是左孩子
                SET_BLACK(parent);//将父节点设置为黑色
                SET_RED(Gparent);//将祖父节点设置为红色
                rightRotation(tree,Gparent);

            }

        }
        else
        {

            //情况一:叔叔节点是红色
            Node* uncle=Gparent->lChild;
            if(uncle && IS_RED(uncle))
            {
                SET_BLACK(uncle);//将叔叔节点设置为黑色
                SET_BLACK(parent);//将父节点设置为黑色
                SET_RED(Gparent);//将祖父节点设置为红色
                node=Gparent;
                continue;

            }
            //情况二:叔叔节点是黑色,当前节点是右孩子
            else if(parent->lChild==node)
            {
                rightRotation(tree,parent);
                Node* temp=parent;
                parent=node;
                node=temp;
            }
            else
            {
                //情况三:叔叔节点是黑色,当前节点是左孩子
                SET_BLACK(parent);//将父节点设置为黑色
                SET_RED(Gparent);//将祖父节点设置为红色
                leftRotation(tree,Gparent);

            }
        }


    }
    SET_BLACK(tree->root);//将根节点设置为黑色

}


void insertRbtree(RBTree* tree,Node* node)//插入节点
{
    Node* preNode=NULL;//前驱节点
    Node* curNode=tree->root;//将当前节点设置为根节点
    while(curNode!=NULL)//判断当前节点是否为空
    {

        preNode=curNode;
        if(node->key<curNode->key)
        {
            curNode=curNode->lChild;//插入节点的值小于当前节点的值就往左走

        }
        else
        {
            curNode=curNode->rChild;
        }
    }
    SET_PARENT(node,preNode);//将插入节点的父节点设置为前驱节点
    if(preNode!=NULL)//判断前驱节点是否为空
    {
        if(preNode->key>node->key)
        {
            preNode->lChild=node;
        }
        else
        {
            preNode->rChild=node;
        }

    }
    else
    {
        tree->root=node;//若前驱节点为空,说明插入节点是根节点
    }
    SET_COLOR(node,RED);//将插入节点设置为红色
    tree->treeSize++;//插入节点后树的大小加1
    adjustNode(tree,node);//调整节点

}

Node* searchNode(Node* root,int key)//查找节点
{
    if(root==NULL||root->key==key)
    {
        return root;
    }
    else if(key<root->key)
    {
        return searchNode(root->lChild,key);
    }
    else
    {
        return searchNode(root->rChild,key);
    }
}

void adjustDelete(RBTree* tree,Node* node,Node* parent) //调整删除节点
{
    Node* brother;//删除节点的兄弟节点
    while(!node||(IS_BLACK(node)&&node!=tree->root))//当节点非空或节点为黑色节点且不是根节点时
    {
        if(parent->lChild==node)//删除节点是左孩子
        {
            brother=parent->rChild;
            if(IS_RED(brother))
            {
                //第一种情况:兄弟节点是红色节点
                SET_BLACK(brother);//将兄弟节点设置为黑色
                SET_RED(parent);//把父节点设置为红色
                leftRotation(tree,parent);//以父节点为支点作左旋操作
                brother=parent->rChild;//将兄弟节点设置为左旋操作后的右孩子


            }
            if((!brother->lChild)&&(!brother->rChild))//判断兄弟节点是否为叶子节点
            {
                //第二种情况:兄弟节点是黑色的
                SET_RED(brother);//将兄弟节点设置为红色
                node=parent;//将当前节点设置为父节点
                parent=PARENTNODE(node);

            }
            else
            {
                if((!brother->rChild)||IS_BLACK(brother->rChild))
                {
                    //第三种情况:兄弟节点是黑色的,兄弟节点的左孩子是红色的,右孩子是黑色的
                    SET_BLACK(brother->lChild);//将兄弟节点的左孩子设置为黑色
                    SET_RED(brother);//将兄弟节点设置为红色
                    rightRotation(tree,brother);//以兄弟节点为支点进行右旋操作
                    brother=parent->rChild;//将兄弟节点设置为父节点的右孩子

                }
                else
                {
                    SET_COLOR(brother,COLOR(parent));//将兄弟节点的颜色设置为父节点的颜色
                    SET_BLACK(parent);//将父节点设置为黑色
                    SET_BLACK(brother->rChild);//将兄弟节点的右孩子设置为黑色
                    leftRotation(tree,parent);//以父节点为支点作左旋操作
                    node=tree->root;//将删除节点设置为根节点
                    break;
                }
            }

        }
        else//删除节点是右孩子
        {
            brother=parent->lChild;
            if(IS_RED(brother))
            {
                //第一种情况:兄弟节点是红色节点
                SET_BLACK(brother);//将兄弟节点设置为黑色
                SET_RED(parent);//把父节点设置为红色
                leftRotation(tree,parent);//以父节点为支点作左旋操作
                brother=parent->lChild;//将兄弟节点设置为左旋操作后的左孩子


            }
            if((!brother->lChild)&&(!brother->rChild))//判断兄弟节点是否为叶子节点
            {
                //第二种情况:兄弟节点是黑色的
                SET_RED(brother);//将兄弟节点设置为红色
                node=parent;//将当前节点设置为父节点
                parent=PARENTNODE(node);

            }
            else
            {
                if((!brother->lChild)||IS_BLACK(brother->lChild))
                {
                    //第三种情况:兄弟节点是黑色的,兄弟节点的左孩子是红色的,右孩子是黑色的
                    SET_BLACK(brother->rChild);//将兄弟节点的左孩子设置为黑色
                    SET_RED(brother);//将兄弟节点设置为红色
                    rightRotation(tree,brother);//以兄弟节点为支点进行右旋操作
                    brother=parent->lChild;//将兄弟节点设置为父节点的右孩子

                }
                else
                {
                    //第四种情况
                    SET_COLOR(brother,COLOR(parent));//将兄弟节点的颜色设置为父节点的颜色
                    SET_BLACK(parent);//将父节点设置为黑色
                    SET_BLACK(brother->lChild);//将兄弟节点的右孩子设置为黑色
                    leftRotation(tree,parent);//以父节点为支点作左旋操作
                    node=tree->root;//将删除节点设置为根节点
                    break;
                }
            }

        }
    }
    if(node)
    {
        SET_BLACK(node);//将节点颜色设置为黑色
    }

}

void deleteNode(RBTree* tree,Node* node)//删除节点
{
    Node* child,*parent;
    int color;
    if((node->lChild!=NULL)&&(node->rChild!=NULL))//判断左右子树是否均非空
    {
        Node* reNode=node;//reNode为替换节点
        reNode=reNode->rChild;//右边找最左边替换
        while(reNode->lChild!=NULL)
        {
            reNode=reNode->lChild;

        }
        if(PARENTNODE(node))//判断删除节点是否为根部
        {
            if(PARENTNODE(node)->lChild==node)//判断删除节点是否为左孩子
            {
                PARENTNODE(node)->lChild=reNode;//用替换节点替换删除节点的位置

            }
            else
            {
                PARENTNODE(node)->rChild=reNode;
            }
        }
        else
        {
            tree->root=reNode;//将根节点设置为替换掉节点
        }
        child=reNode->rChild;
        parent=PARENTNODE(reNode);
        color=COLOR(reNode);
        if(parent==node)
        {
            parent=reNode;
        }
        else
        {
            if(child)
            {
                SET_PARENT(child,parent);
            }
            parent->lChild=child;
            reNode->rChild=node->rChild;
            SET_PARENT(node->rChild,reNode);
        }
        //调整替换节点的父节点
        reNode->parentNode=node->parentNode;
        reNode->color=node->color;
        reNode->lChild=node->lChild;
        //调整删除节点的父节点
        node->lChild->parentNode=reNode;
        if(color==BLACK)//如果删除节点为黑色节点,则需要调整节点
        {
            adjustDelete(tree,child,parent);
        }
        free(node);//释放删除节点
        node=NULL;
        return ;


    }
    //考虑只有单边的情况
    if(node->lChild!=NULL)//如果只有左孩子
    {
        child=node->lChild;
    }
    else//如果只有右孩子
    {
        child=node->rChild;
    }
    parent=node->parentNode;
    color=node->color;
    if(parent)//判断删除节点的父节点是否为空
    {
        if(parent->lChild==node)
        {
            parent->lChild=child;
        }
        else
        {
            parent->rChild=child;
        }
    }
    else
    {

        tree->root=child;
    }
    if(color==BLACK)//如果删除节点颜色为黑色,需要进行调整
    {
        adjustDelete(tree,child,parent);
    }
    free(node);
    node=NULL;
}
void deleteRbtree(RBTree* tree,int key)//根据已知数值删除节点
{
    Node* result=searchNode(tree->root,key);//先查找要删除的节点
    if(result!=NULL)
    {
        deleteNode(tree,result);
    }
}







  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值