二叉叉树树树树

目录

 7-4

 7-3


 

 7-4

输入样例:

2
1 1
4 1 4 0 2

输出样例:

1
1
2 4 1
3

 

u1s1这个题目虚节点会不会合法给出我有点不大明白

不知道虚节点下面到底有没有数

概念理解应该也没有问题

完全二叉树:用二维数组记录 且 数组前面部分都能填满的二叉树

中序遍历: 左    根    右

深度: 层数(用数学公式得)应该这里没问题(换底公式)

由pow(2,n)=lay  得到如下公式
int t = (ceil)(log(n +1.0) / log(2.0)) ;//深度

之前还用了这个计算公式

int t = (int)(log(n *1.0) / log(2.0)) +1;//深度

 感觉这个会有问题,但是改了后也不对

思路:

找到最左端子叶(遇到0终止下找)

ps:一开始是从左下角开始找起
   但是如果根节点和左下角的值
   之间有虚节点也会找到错误的开端
   如:1 0 2 3 4 0 6
   于是从根节点开始找最左子叶(遇到0终止)

打印      给标记

返回上一层

检测左右分支是否都被标记

是,一直向上返回至没被标记的分支

否,进入未被标记的分支进入(都是先左子树 后右子树)

终止条件:i=1  (回到根节点)并且i=1已经被标记

代码:

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<cmath>
using namespace std;
//string a = "1245367", b = "4251637";
//string a, b;
int T, n;
int a[1010];//数据数组
int b[1010];//标记数组
int i, j, k;
int main()
{
   /*debug logs
    *样例 one  1 2 3 4 0 5
    *     two  1 2 3 0 4 0 5
    *     three1 2 3 4 5 0 0 6
    *
    */
    cin >> T;
    while (T--)
    {
        k = 0;//格式控制
        memset(b, 0, sizeof(b));
        memset(a, 0, sizeof(a));

        cin >> n;
        //
        int t = (ceil)(log(n +1.0) / log(2.0)) ;//深度

        for (i = 1; i <= n; i++)
        {
            cin >> a[i];
        }
        i = 1;
        int temp = t;
        /*
        while (--t)//找初始下标(最左子叶  为虚节点没关系)
        {
            i = i * 2;
        }
        */
        while(a[2*i]!=0)
            i*=2;
        //
        //printf("开始下标:%d\n", i);
        //system("pause");
        while (1)
        {

            if (a[i] != 0&&b[i]!=1)// b[i]!=1  写不写没影响貌似
            {
                if (k != 0)
                {
                    printf(" ");
                }
                printf("%d",a[i]);
                b[i] = 1;
                k++;
            }


            if (a[2 * i] != 0 && b[2 * i] == 0)//左孩子未被标记且值非0
            {
                i = 2 * i;
               // continue;
            }
            else if ( a[2 * i + 1] != 0 &&b[2 * i + 1]==0)//右孩子
            {
                //要找右孩子的左叶子
                i = 2 * i + 1;
                while (a[2 * i] != 0&&b[2*i]==0)
                    i = i * 2;

                //continue;
            }
            else//左右都被标记 或 值为0
            {
                i = i / 2;       //返回上一级
                while (b[i] == 1)//上一级被标记 一直返回
                {
                    i = i / 2;   //第一次遇见i=1不会终止
                    if (i == 0)
                        break;//终止
                }
                if (i == 0)
                    break;//终止
            }
        }
        printf("\n");
        printf("%d\n", temp);

    }
}

有点小难找了,不知道是错在哪里

下面是另一份错误代码 

经过1时转换成搜索左子树模式

但是若是最后一行中间是虚节点

而最右下角是实节点就会被忽略

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<cmath>
using namespace std;
//string a = "1245367", b = "4251637";
//string a, b;
int T, n;
int a[1010];//数据数组
int b[1010];//标记数组
int i, j, k;
int main()
{
   /*debug日志
    *样例 one  123405
    *     two  1 2 3 0 4 0 5
    *     three1 2 3 4 5 0 0 6 
    *     1 2 3 4 5 6 7 8 0 0 0 0 0 0 9 找不到
    */
    cin >> T;
    while (T--)
    {
        k = 0;//格式控制
        memset(b, 0, sizeof(b));
        memset(a, 0, sizeof(a));

        cin >> n;
        //
        int t = (int)(log(n * 1.0) / log(2.0)) + 1;//深度
        int num = 0;//节点数
        for (i = 1; i <= n; i++)
        {
            cin >> a[i];
            if (a[i] != 0)
                num++;
        }
        if (n == 1)
        {
            cout << a[1]<<endl;
            cout << "1" << endl;
            continue;
        }
            
        if(n==2)
        {
            cout <<a[2]<<" "<<a[1]<<endl;
            cout << "2" << endl;
            continue;
        }
        i = 1;

        int temp = t;
        t--;
        while (--t)//找初始下标
        {
            i = i * 2;
        }
        //倒数的二层左端开始
        //左子树模式
        while (1)
        {
            if (a[2 * i] != 0&& b[2 * i] ==0)
            {
                if (k != 0)
                    cout << " ";
                cout << a[2 * i];
                b[2 * i] = 1;
                k++;
            }
            if (k != 0&&a[i]!=0)
                cout << " ";
            cout << a[i];
            b[i] = 1;
            k++;
            if (i == 1)
                break;
            
            if (a[2 * i + 1] != 0 && b[2 * i + 1] == 0)
            {
                    if (k != 0)
                        cout << " ";
                    cout << a[2 * i + 1];
                    b[2 * i + 1] = 1;
                    k++;
            }
            i /= 2;
        }
        //右子树模式
        i = 3;
        while (i * 2 < num)//找到的a[i]不为0
        {
            i *= 2;
        }
        if(k<num)
        while (1)
        {
            if (a[2 * i] != 0 && b[2 * i] == 0)
            {
                if (k != 0)
                    cout << " ";
                cout << a[2 * i];
                b[2 * i] = 1;
                k++;
                if (k == num)
                    break;
            }
            if (k != 0 )
                cout << " ";
            cout << a[i];
            b[i] = 1;
            k++;
            if (k == num)
                break;
            

            if (a[2 * i + 1] != 0 && b[2 * i + 1] == 0)
            {
                if (k != 0)
                    cout << " ";
                cout << a[2 * i + 1];
                b[2 * i + 1] = 1;
                k++;
                if (k == num)
                    break;
            }
            i /= 2;
        }
        printf("\n");
        printf("%d\n", temp);

    }
}

7-3

 一个很巧妙的方法

根据前序遍历特点

将前序遍历的数字    看做   中序遍历的数字里面的根节点

而当前根节点又将该区间分成两部分

如果左边还有数(分支)也就是pos>left2

进入左支

右边同理

都没有数开始打印

返回上一层,继续上一层的任务,和常规递归很像,但是更巧妙

这题是数值,不好用string

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
//string a = "1245367", b = "4251637";
//string a, b;
int  a[100], b[100];
void pro_digui(int L1, int R1, int L2, int R2);
int n;
int main()
{

    //cin >> a >> b;
    cin >> n;
    if(n)
    {
        for (int i = 0; i < n; i++)
        {
            //scanf_s("%d", &a[i]);
            cin >> a[i];
        }
        //getchar();
        for (int i = 0; i < n; i++)
        {
            //scanf_s("%d", &b[i]);
            cin >> b[i];
        }
        pro_digui(0, n-1, 0,n-1);
    }


}
void pro_digui(int L1, int R1, int L2, int R2)
{
    int pos = 0;
    int i, j;
    for (i = 0; i < n; i++)
    {
        if (b[i] == a[L1])
        {
             pos = i;
            break;
        }

    }


    if (pos > L2)
    {
        pro_digui(L1 + 1, R1 + pos - L2, L2, pos - 1);
    }
    if (pos < R2)
    {
        pro_digui(L1 + pos - L2 + 1, R1, pos + 1, R2);
    }
    cout << a[L1]<<" ";
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值