scau 18959 二叉树的之字形遍历

Description

题目来源:字节跳动测试题

给定一个二叉树,返回该二叉树的之字形层序遍历,(第一层从左向右,下一层从右向左,一直这样交替)
例如:
给定的二叉树是{3,9,20,15,7,#,#}
该二叉树之字形层序遍历的结果是
3
20 9
15 7

 

输入格式

一行字符串,只包含大写字母和#。
此处采用完全二叉树的顺序存储结构。

输出格式

若干行,之字形输出树的结点,每一行输出树的一层。

输入样例

ABC###D##

输出样例

A
C B
D

       嗯……说实话,这道题把我给看傻了,我想着二叉树不就只有先序遍历、中序遍历和后序遍历吗?怎样调用这三个函数才能实现之字形输出呢?

       我发现我想不出来,于是就打开了CSDN,找到了一个作者认为很“笨”而我认为很绝妙的方法。https://blog.csdn.net/m0_52463794/article/details/117619762 

        那我就简单的记个笔记叭。

       首先,你要知道完全二叉树的顺序存储结构是什么。没错,完全二叉树的顺序存储结构是数组,所以说我一开始想的先序、中序、后序遍历和这道题是没啥太大关系的。

       然后,这道题用了一些有关二叉树的性质。我简单介绍一下。

性质1  在二叉树的第i层上至多有2^(i-1)个结点。

       我们就可以知道第i层的第1个结点的下标为2^(i-1)-1,第i层的最后一个结点的下标为2^i-2

性质2  深度为k的二叉树至多有2^k-1个结点。

       通过性质2,我们可以根据结点的个数来求层数。所以要先处理数组,求最后一个字母的下标。已知最后一个字母的下标,也就是知道了结点的个数,设结点个数为len,令2^k-1=len,就可以求出深度k了

性质3 具有n个结点的完全二叉树的深度为(emm,写的比较丑)

       性质3可以替换性质2,这样的话就可以少写两个循环了(少写一个求最后字母下标的循环和一个求k的循环,我看的那位作者写的博客就是用的性质2,我后来翻了翻书,发现了求完全二叉树深度的这个公式)。 

       这是通过性质2求深度k。

    int i,j,len=0,k;
    for(i=0; i<100005; i++) //记录最后一个大写字母下标
    {
        if(s[i]<='Z' && s[i]>='A')
            len=i;
    }
    len=len+1;//数组从0开始储存
    for(k=1; ;k++) //寻找数组代表的数的最大层数
    {
        if(pow(2,k)-1>=len)
            break;
    }

        这是通过性质3求深度k(可以少写很多字)

    len=strlen(s);
    k=log(len)/log(2)+1;

       然后之字形输出的话,就定义一个flag,flag=1的时候从左往右,flag=0的时候从右往左。每次反向的时候把第i层的第一个结点下标和最后一个结点下标的值换一下就行,可能说的不清楚,看看代码就明白了。

#include <cstdio>
#include <cstring>
#include <math.h>
#include <iostream>

using namespace std;

char s[100005]={'\0'};
int main()
{
    scanf("%s",s);
    int i,j,len=0,k;
    /*for(i=0; i<100005; i++) //记录最后一个大写字母下标
    {
        if(s[i]<='Z' && s[i]>='A')
            len=i;
    }
    len=len+1;//数组从0开始储存
    for(k=1; ;k++) //寻找数组代表的数的最大层数
    {
        if(pow(2,k)-1>=len)
            break;
    }*/
    len=strlen(s);
    k=log(len)/log(2)+1;
    int flag=1;//控制方向
    for(i=1; i<=k; i++) //遍历
    {
        int Start=pow(2,i-1)-1;//第i层第一个结点下标
        int End=pow(2,i)-2;//第i层最后一个结点的下标
        if(flag==1)//从左到右输出
        {
            for(j=Start; j<=End; j++)
            {
                if(s[j]!='#') printf("%c ",s[j]);
            }
            flag=0;//更新flag
        }
        else//从右到左输出
        {
            for(j=End; j>=Start; j--)
            {
                if(s[j]!='#') printf("%c ",s[j]);
            }
            flag=1;//更新flag
        }
        printf("\n");
    }
    return 0;
}

 4.23更新

不行不行,用性质3做的话oj上过不了,用性质2就能过(也就是下面这个),我也不知道为啥。

for(i=0; i<100005; i++) //记录最后一个大写字母下标
    {
        if(s[i]<='Z' && s[i]>='A')
            len=i;
    }
    len=len+1;//数组从0开始储存
    for(k=1; ;k++) //寻找数组代表的数的最大层数
    {
        if(pow(2,k)-1>=len)
            break;
    }
/*len=strlen(s);
k=log(len)/log(2)+1;*/ //这个过不了

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值