• 多叉树(森林)转二叉树


    本来不怎么想写这个,但发现网上的都是“残疾”博客,讲得不是很详细,所以我还是要写一下。
    多叉转二叉有“左儿子右兄弟”的说法,然而对于什么都不知道的小白,这句话没有任何用……

    思路

    大体就两步,很好理解,如图是用来举栗的多叉树:

    兄弟连

    将所有的兄弟间连一条线,如图:

    右子断

    将所有右儿子与父亲的边删掉,如图:

    其他

    事实上这已经是一棵二叉树了,还有一点小细节。

    调整层次

    这里写图片描述
    很容易发现,“兄弟”(即黄色线相连的结点)都在它们的大哥右子树中,且根结点一定没有右儿子(因为根结点没有兄弟)。

    森林的处理

    有的坑爹题目,转为二叉树后有多个结点的父亲都为0(即为根结点),如图:
    这里写图片描述
    (原谅我直接copy的第一棵树,不过没影响)解决这个很容易,从右到左依次将根结点接到它前一个根结点的右儿子上即可:
    这里写图片描述

    实现

    连接兄弟&切断右儿子

    这里介绍最好理解的方法:
    输入一对关系,如x,y(表示y为x的儿子)
    判断:x有没有左儿子
    没有:y直接成为x的左儿子;
    有:设x的左儿子为x.l,右儿子为x.r,就找到x.l的右儿子的右儿子的右儿子……
    为什么不用切断右儿子?因为根本就还没有连接右儿子!
    如图:
    这里写图片描述

    就这样。(这么简单?!)
    代码:

    if(tree[i].l==0)  
    {  
        tree[i].l=j;  
        tree[j].f=i;//改变父子关系  
    }  
    else  
    {  
        int t=tree[i].l;  
        while(tree[t].r)  
            t=tree[t].r;//找到x左子树中最右边的结点  
        tree[t].r=j;  
        tree[j].f=t;  
    }  

    森林

    按照刚刚说的硬行实现即可:

    for(int i=1;i<=N;i++)  
        if(!tree[i].f)  
            root[++rs]=i;//找到所有根结点并保存
    for(int i=rs;i>1;i--)  
    {  
        tree[root[i-1]].r=root[i];
        tree[root[i]].f=root[i-1];//处理根结点
    }

    完整代码

    恶心的是这道题兄弟之间要要求顺序(编号小的在左边),所以不能边输入边处理

    //输入N,M表示节点数和边数,再输入M组边关系,从1到N输出每个结点的父亲,根节点父亲为0 
    #include<cstdio> 
    #include<algorithm>  
    using namespace std;  
    void read(int &x)  
    {  
        int f=1;x=0;char s=getchar();  
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}  
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}  
        x*=f;  
    }  
    #define MAXN 100  
    struct node  
    {  
        int l,r,f;  
    }tree[MAXN+5];  
    int N,M;  
    int root[MAXN+5],rs;  
    bool d[MAXN+5][MAXN+5];  
    void rtb()//处理森林
    {  
        for(int i=1;i<=N;i++)  
            if(!tree[i].f)  
                root[++rs]=i;  
        for(int i=rs;i>1;i--)  
        {  
            tree[root[i-1]].r=root[i];  
            tree[root[i]].f=root[i-1];  
        }  
    }  
    int main()  
    {  
        read(N),read(M);  
        for(int i=1;i<=M;i++)  
        {  
            int x,y;  
            read(x),read(y);  
            d[x][y]=1;//先保存起来
        }  
        for(int i=1;i<=N;i++)//再处理
            for(int j=1;j<=N;j++)  
                if(d[i][j])  
                {  
                    if(tree[i].l==0)  
                    {  
                        tree[i].l=j;  
                        tree[j].f=i;  
                    }  
                    else  
                    {
                        int t=tree[i].l;
                        while(tree[t].r) t=tree[t].r;
                        tree[t].r=j;
                        tree[j].f=t;
                    }
                }
        rtb();
        for(int i=1;i<=N;i++)  
        {  
            if(i<N) printf("%d
    ",tree[i].f);  
            else printf("%d",tree[i].f);  
        }  
    }  
  • 相关阅读:
    ubuntu之路——day14 只用python的numpy在底层实现多层神经网络
    2019春 软件工程 助教总结
    ubuntu之路——day13 只用python的numpy在较为底层的阶段实现单隐含层神经网络
    ubuntu之路——day12.1 不用tf和torch 只用python的numpy在较为底层的阶段实现简单神经网络
    ubuntu之路——day11.7 end-to-end deep learning
    ubuntu之路——day11.6 多任务学习
    ubuntu之路——day11.5 迁移学习
    mysql 主从复制 (1)
    Windows下Nginx的启动、停止、重启等命令
    mysql-5.7.17-winx64压缩版的安装包下载和安装配置
  • 原文地址:https://www.cnblogs.com/LinqiongTaoist/p/7203730.html
Copyright © 2020-2023  润新知