用bfs求dfs序(先序遍历序)

给你一棵树
求这棵树的dfs序
但是树的深度会爆系统栈
那么如何求出dfs序?
当然,空间足够
一般情况下有两种做法
1. 手写栈跑dfs
2. 跑bfs
第一种太过简单
我不予简介
我们主要说第二种
首先我们知道dfs序就是要先遍历左子树
那么我们是不是可以用一种神奇的方法
在bfs序的基础上做出dfs序
首先
我们知道
无论是dfs序还是bfs序
根节点一定在第一个位置
同时bfs序可得出一个分层结构
正序遍历bfs序到当前点时,当前点的父亲一定被遍历过
那么我们可以这样考虑
是否可以通过父亲的位置来求出当前点的位置?
答案是肯定的啊
dfs序中同一深度的儿子顺序和bfs序中相同
同一父亲的不同儿子在dfs序中位置值相差的数值
是以两儿子中较左儿子为根的子树的节点的数量
那么我们就可以在bfs时维护一个size
然后遍历bfs序
维护一个last表示从上一个点推得的这一点应在的位置
如果当前点和前一个点父亲不同
那么last为当前点父亲的位置+1
如果当前点和前一个点父亲相同
那么last+=前一个点的size
遍历后就求出了dfs序!
代码如下

#include <cstdio>
#include <cstdlib>
#include <cctype>
char getc()
{
    static const int LEN = 1<<15;
    static char buf[LEN],*S=buf,*T=buf;
    if(S == T)
    {
        T = (S=buf)+fread(buf,1,LEN,stdin);
        if(S == T)return EOF;
    }
    return *S++;
}
int read()
{
    static char ch;
    static int D;
    while(!isdigit(ch=getc()));
    for(D=ch-'0'; isdigit(ch=getc());)
        D=(D<<3)+(D<<1)+(ch-'0');
    return D;
}
int n,idx;
int to[2000000],next[2000000],head[1000001],
    q[1000001],fa[1000001],size[1000001],
    dfs[1000001],zz[1000001];
void add(int x,int y)
{
    to[++idx]=y;
    next[idx]=head[x];
    head[x]=idx;
    to[++idx]=x;
    next[idx]=head[y];
    head[y]=idx;
    return ;
}
void bfs()
{
    int l=0,r=0;
    q[r++]=1;
    while(l!=r)
    {
        int x=q[l++];
        size[x]=1;
        for(int i=head[x];i;i=next[i])
            if(to[i]!=fa[x])
            {
                fa[to[i]]=x;
                q[r++]=to[i];
            }
    }
    for(int i=n-1;i>=0;--i)
        size[fa[q[i]]]+=size[q[i]];
    return ;
}
int main()
{
    n=read();
    for(int i=1;i<n;++i)
    {
        int a=read(),b=read();
        add(a,b);
    }
    bfs();
    dfs[1]=1;
    zz[1]=2;
    int last;
    for(int i=1;i<n;++i)
    {
        if(fa[q[i]]!=fa[q[i-1]])
            last=zz[fa[q[i]]];
        else
            (last+=size[q[i-1]]);
        dfs[last]=q[i];
        zz[q[i]]=last+1;
    }
    for(int i=1;i<=n;++i)
        printf("%d\n",dfs[i]);
    return 0;
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值