后序遍历满二叉树(洛谷P1087 FBI树)

后序遍历满二叉树(洛谷P1087 FBI树)

题目

见题目链接FBI树 - 洛谷
题目链接

输入

见题目链接

输出

见题目链接

样例

见题目链接

题解

本题可划分为两部分的问题来进行解决,首先是利用给定的01串来构造一个满二叉树,其中要对01串进行类似于二分的操作,因此我们可以使用递归的思路,将01串不断二分,并得到相应节点对应的字母(F、B、I),由此构成一颗满二叉树。我们采用一个带有两个指针域的结构体链表来存储这颗树,两个指针分别指向该节点的左儿子和右儿子。这样构造的好处是在进行下一步后序遍历时,可以方便地找到当前节点的两个儿子。构造完满二叉树后,就可以开始对其进行后序遍历了。根据“左右根”的思路,我们可以用类似DFS(深度优先搜索)的方式来进行后序遍历,每次寻找到最深的那个节点,遍历结束后回溯到上一层,重复这两个操作,直到遍历完全部的节点。具体的代码实现还是运用递归的思想。

代码

#include <stdio.h>
#include <stdlib.h>

typedef struct tree{
    char flag;
    struct tree *next_1, *next_2;
}LinkList;

LinkList *head;

int makeString(char* str, LinkList *node, int len){
    LinkList *node1, *node2;
    int flag0 = 0;
    int flag1 = 0;
    node1 = (LinkList*)malloc(sizeof(LinkList));
    node2 = (LinkList*)malloc(sizeof(LinkList));
    if (len > 1){
        if (head != node){
            node->next_1 = node1;
            node->next_2 = node2;
            for (int i = 0; i < len/2;i++){
                if (str[i] == '0')
                    flag0 = 1;
                if (str[i] == '1')
                    flag1 = 1;
            }
            if (flag0 == 1 && flag1 == 1)
                node1->flag = 'F';
            if (flag0 == 1 && flag1 == 0)
                node1->flag = 'B';
            if (flag0 == 0 && flag1 == 1)
                node1->flag = 'I';
            flag0 = 0;
            flag1 = 0;
            for (int i = len/2; i < len;i++){
                if (str[i] == '0')
                    flag0 = 1;
                if (str[i] == '1')
                    flag1 = 1;
            }
            if (flag0 == 1 && flag1 == 1)
                node2->flag = 'F';
            if (flag0 == 1 && flag1 == 0)
                node2->flag = 'B';
            if (flag0 == 0 && flag1 == 1)
                node2->flag = 'I';
            makeString(str, node1, len/2);
            makeString(str+len/2, node2, len/2);
        }else{
            node->next_1 = node1;
            for (int I = 0; I < len;i++){
                if (str[i] == '0')
                    flag0 = 1;
                if (str[i] == '1')
                    flag1 = 1;
            }
            if (flag0 == 1 && flag1 == 1)
                node1->flag = 'F';
            if (flag0 == 1 && flag1 == 0)
                node1->flag = 'B';
            if (flag0 == 0 && flag1 == 1)
                node1->flag = 'I';
            makeString(str, node1, len);
        }
    }else{
        if (head != node){
            node->next_1 = NULL;
            node->next_2 = NULL;
        }
        else{
            node->next_1 = node1;
            if (str[0] == '0')
                node1->flag = 'B';
            if (str[0] == '1')
                node1->flag = 'I';
            node1->next_1 = NULL;
            node2->next_2 = NULL;
        }
    }
    return 0;
}

int search(LinkList *node){
    if ((node->next_1 == NULL) && (node->next_2 == NULL)){
        printf("%c", node->flag);
    }else{
        search(node->next_1);
        search(node->next_2);
        printf("%c", node->flag);
    }
    return 0;
}

int main(){
    char str[1025];
    int n,sum;
    head = (LinkList*)malloc(sizeof(LinkList));
    scanf("%d", &n);
    sum = 1;
    for (int i = 0; i < n;i++){
        sum = sum * 2;
    }
    sum = sum * 2 - 1;
    scanf("%s", str);
    makeString(str, head, (sum+1)/2);
    search(head->next_1);
    return 0;
}

代码解释

链表结构体声明:

typedef struct tree{
    char flag;
    struct tree *next_1, *next_2; //next_1指向左儿子,next_2指向右儿子
}LinkList;

构造满二叉树:

int makeString(char* str, LinkList *node, int len){ // str是字符串指针 node是指向当前节点的链表指针 len是当前节点对应的字符串的长度
    LinkList *node1, *node2;
    int flag0 = 0;
    int flag1 = 0;
    node1 = (LinkList*)malloc(sizeof(LinkList));
    node2 = (LinkList*)malloc(sizeof(LinkList));
    if (len > 1){
        if (head != node){ //如果当前节点不是头节点,则构造两个儿子节点,并将当前节点指向这两个儿子节点
            node->next_1 = node1;
            node->next_2 = node2;
            //求得节点的char值
            for (int i = 0; i < len/2;i++){
                if (str[i] == '0')
                    flag0 = 1;
                if (str[i] == '1')
                    flag1 = 1;
            }
            if (flag0 == 1 && flag1 == 1)
                node1->flag = 'F';
            if (flag0 == 1 && flag1 == 0)
                node1->flag = 'B';
            if (flag0 == 0 && flag1 == 1)
                node1->flag = 'I';
            flag0 = 0;
            flag1 = 0;
            for (int i = len/2; i < len;i++){
                if (str[i] == '0')
                    flag0 = 1;
                if (str[i] == '1')
                    flag1 = 1;
            }
            if (flag0 == 1 && flag1 == 1)
                node2->flag = 'F';
            if (flag0 == 1 && flag1 == 0)
                node2->flag = 'B';
            if (flag0 == 0 && flag1 == 1)
                node2->flag = 'I';
            //对两个儿子节点重复构造的过程(递归)
            makeString(str, node1, len/2);
            makeString(str+len/2, node2, len/2);
        }else{
            //如果当前节点是头节点,则创建一个根节点,并将头节点指向这个根节点
            node->next_1 = node1;
            for (int I = 0; I < len;i++){
                if (str[i] == '0')
                    flag0 = 1;
                if (str[i] == '1')
                    flag1 = 1;
            }
            if (flag0 == 1 && flag1 == 1)
                node1->flag = 'F';
            if (flag0 == 1 && flag1 == 0)
                node1->flag = 'B';
            if (flag0 == 0 && flag1 == 1)
                node1->flag = 'I';
            makeString(str, node1, len);
        }
    }else{
        //如果01串的长度为1,有两种情况,一个是经过多次二分,01串分解成了只剩一个char的串,无法继续再二分,因此当前节点不存在儿子,将两个指向儿子的指针设为NULL;另一种情况是,输入的01串总共只有一个char,此时要建立一个根节点,并将头节点的指针指向它,将这个根节点的两个指向儿子的指针设为NULL。
        if (head != node){
            node->next_1 = NULL;
            node->next_2 = NULL;
        }
        else{
            node->next_1 = node1;
            if (str[0] == '0')
                node1->flag = 'B';
            if (str[0] == '1')
                node1->flag = 'I';
            node1->next_1 = NULL;
            node2->next_2 = NULL;
        }
    }
    //退出当前函数调用(回溯)
    return 0;
}

进行后序遍历:

int search(LinkList *node){
    if ((node->next_1 == NULL) && (node->next_2 == NULL)){
        printf("%c", node->flag); //如果找到了叶子节点,说明已经到达了树的最深处,此时应输出当前节点的char值,并回溯到上一个节点。
    }else{
        //如果没有找到叶子节点,则继续按照“左右根”的顺序查找下一个节点
        search(node->next_1);
        search(node->next_2);
        printf("%c", node->flag); //当儿子节点都遍历完了之后,回溯到此节点,输出此节点的char值
    }
    return 0;//退出当前函数调用(回溯)
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值