红黑树

红黑树
时间限制:3000 ms | 内存限制:65535 KB
难度:3

描述

什么是红黑树呢?顾名思义,跟枣树类似,红黑树是一种叶子是黑色果子是红色的树。。。

当然,这个是我说的。。。

《算法导论》上可不是这么说的:

如果一个二叉查找树满足下面的红黑性质,那么则为一个红黑树。

1)每个节点或是红的,或者是黑的。

2)每个叶子节点(NIL)是黑色的

3)如果一个节点是红色的,那么他的两个儿子都是黑的。

4)根节点是黑色的。

5)对于每个节点,从该节点到子孙节点的所有路径上包含相同数目的黑色节点。

我们在整个过程中会用到这些性质,当然,为了公平起见,其实即使你不知道这些性质,这个题目也是可以完成的(为什么不早说。。。。)。在红黑树的各种操作中,其核心操作被称为旋转,那么什么是旋转呢,我们来看一个例子:

假设我们这里截取红黑树的一部分,放在左边,通过操作如果可以把他转化为右边的形式,那么我们就称将根为x的子树进行了左旋,反之我们称将根为Y的树进行了右旋:

恰好慢板同学把自己红黑树弄乱了,然后请你帮忙进行修复,他将向你描述他的红黑树(混乱的。。。)。然后告诉他需要用哪种方式旋转某个节点。在你完成工作之后,直接向大黄提交新的树的中序遍历结果就好了。



Hint:

在这里好心的慢板同学给你简单的解释下样例:

最开始的时候树的样子是这样的:

    0

  /    \

1       2

然后对于标号为0的节点进行右旋,结果将变为:

 1

  \

   0

    \

      2

然后呢。。。

中序遍历?这个是什么东西,哪个人可以告诉我下。。。。

输入
输入分两部分:
第一部分:一个整数T(1<=T<=10),表示测试的组数。
第二部分:第一行是一个数字N,表示红黑树的节点个数。0

#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>


using namespace std;


struct LNode
{
    int l,r;//左子树 右子树
    int p;//记录父亲节点
}tree[1<<12];
void in(int x)
{
    if(x == -1) return ;
    in(tree[x].l);
    printf("%d\n",x);
    in(tree[x].r);
}
int main()
{
    int ncase;
    scanf("%d",&ncase);
    while(ncase--)
    {
        int n;//n个节点
        scanf("%d",&n);
        memset(tree,-1,sizeof(tree));
        tree[0].p = -1;
        for(int i =0;i<n;i++)
        {
            int f,s1,s2;
            scanf("%d%d%d",&f,&s1,&s2);
            tree[f].l = s1;
            tree[f].r = s2;
            if(s1 != -1)
                tree[s1].p = f;
            if(s2 != -1 )
                tree[s2].p = f;
        }
        int m;
        scanf("%d",&m);
        int rt = 0;
        while(m--)
        {
            int indx,op;
            scanf("%d%d",&indx ,&op);
            if(op)//右旋
            {
                if(tree[indx].l != -1)//有左儿子
                {
                    int p = tree[indx].p;
                    int x = tree[indx].l;
                    //交换父亲节点
                    if(tree[indx].p == -1) rt = x;
                    tree[indx].p = x;
                    tree[x].p = p;
                    //判断是左儿子还是右儿子
                    if(p !=-1 && tree[p].l == indx)
                    {
                        tree[p].l = x;
                    }
                    else if(p != -1)
                    {
                        tree[p].r = x;
                    }
                    //上面的代码关于父亲节点全部修改完毕
                    int tmp = tree[x].r;
                    tree[x].r = indx;
                    tree[indx].l = tmp;
                }
            }
            else
            {
                if(tree[indx].r !=-1)
                {
                   int p = tree[indx].p;
                   int x = tree[indx].r;
                   if(tree[indx].p == -1) rt = x;
                    tree[indx].p = x;
                   tree[x].p = p;
                  if(p !=-1 && tree[p].l == indx)
                    {
                        tree[p].l = x;
                    }
                    else if(p != -1)
                    {
                        tree[p].r = x;
                    }
                    int tmp = tree[x].l;
                    tree[x].l = indx;
                    tree[indx].r = tmp;
                }
            }
        }
        in(rt);
        if(ncase) cout<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值