利用前序和后序遍历序列构建真二叉树的构建

利用前序和后序序列构建真二叉树

一般来讲,给定二叉树的先序遍历序列和后序遍历序列,不能唯一确定这棵二叉树。但 是,对于真
二叉树来讲,给定它的先序遍历序列 pre 和后序遍历序列 post,可以唯一确定这 棵真二叉树。所谓真
二叉树是指每个内部节点都有两个孩子的二叉树。
根据真二叉树的先序遍历序列 pre 和后序遍历序列 post,编写一个实现真二叉树的构造 及中序遍
历的程序,要求如下:
(1)具有操作界面;
(2)可以测试多组数据,每组数据的真二叉树先序遍历序列 pre、后序遍历序列 post 通过键盘输

( 3 ) 将 先 序 遍 历 序 列 pre 、 后 序 遍 历 序 列 post 、 中 序 遍 历 序 列 in 保 存 到 文 本 文 件
proper-bitree.txt 中, 格式如下:
真二叉树的先序遍历序列 pre
真二叉树的后序遍历序列 post
真二叉树的中序遍历序列 in

分析:二叉树前序遍历的第一个元素和后序遍历的最后一个元素为树根,后序遍历序列的倒数第二个元素为右子树的根,前序遍历中右子树的根的前面的元素均为左子树元素,从而分隔左右子树的元素,据此可以采用递归依次构建每一棵子树。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
typedef struct BitNode
{
    char data;
    struct BitNode *lchild;
    struct BitNode *rchild;
} BitNode;
 
BitNode *Creat_ProperBiTree(char *pre, char *post, int length, int *tag); //前序后序转中序
void InOrderTraverse(BitNode*T);
 
int main(void)
{
    int c;
    while(1)
    {
        printf("请开始选择:0、构造真二叉树,1、退出\n");
        scanf("%d", &c);
        fflush(stdin);
        switch(c)
        {
        case 0:
        {
            FILE *fp ;
            int tag = 0;//标记错误,0为无错误
            if((fp = fopen("proper-bitree.txt", "a")) == NULL)
            {
                printf("打开文件失败\n");
                exit(EXIT_FAILURE);
            }
            system("cls");
            char pre[1024];
            char post[1024];
            //文件写入前序序列
            printf("请输入前序输出序列(不要有空格)\n");
            gets(pre);
            fputs(pre, fp);
            fprintf(fp, "\n");
            //文件写入后序序列
            printf("请输入后序输出序列(不要有空格)\n");
            gets(post);
            fputs(post, fp);
            fprintf(fp, "\n");
            fclose(fp);
            int prelength = strlen(pre);
            int postlength = strlen(post);
            if(prelength != postlength || prelength % 2 == 0 || postlength % 2 == 0)
            {
                tag = 1;//长度不符合要求,设置错误
            }
            //开始构造真二叉树
            BitNode* T;
            T = Creat_ProperBiTree(pre, post, prelength, &tag);//tag指示是否出错
 
            if(tag == 0)
            {
                InOrderTraverse(T);
                if((fp = fopen("proper-bitree.txt", "a")) == NULL)
                {
                    printf("打开文件失败\n");
                    exit(EXIT_FAILURE);
                }
                fprintf(fp, "\n");//行末增加换行
                fclose(fp);
                printf("结果已写入文件\n");
            }
            else
            {
                if((fp = fopen("proper-bitree.txt", "a")) == NULL)
                {
                    printf("打开文件失败\n");
                    exit(EXIT_FAILURE);
                }
                fprintf(fp, "对不起,输入的序列无法构成真二叉树\n");
                fclose(fp);
                printf("结果已写入文件\n");
            }
            system("pause");
        }
        break;
        case 1:
        {
            return 0;
            break;
        }
        default:
            printf("输入错误,请重新输入\n");
            break;
        }
    }
    return 0;
}
 
 
void InOrderTraverse(BitNode*T)
{
    if(T)
    {
        InOrderTraverse(T->lchild);
        //在文件中写入中序遍历序列
        FILE *fp1;
        if((fp1 = fopen("proper-bitree.txt", "a")) == NULL)
        {
            printf("打开文件失败\n");
            exit(EXIT_FAILURE);
        }
        fputc(T->data, fp1);
        fclose(fp1);
        InOrderTraverse(T->rchild);
    }
}
 
BitNode *Creat_ProperBiTree(char *pre, char *post, int length, int *tag) //前序后序转中序
{
    if(length == 1)//有一个节点,必为根
    {
        BitNode* T = (BitNode*)malloc(sizeof(BitNode));
        if(pre[0] == post[0])//唯一的节点相同
        {
            T->data = pre[0];
            T->lchild = NULL;
            T->rchild = NULL;
            return T;
        }
        else//唯一的节点不相同,必错误
        {
            *tag = 1;
            return NULL;
        }
    }
    if(length % 2 == 0)//序列长度为偶数,无法构成真二叉树
    {
        *tag = 1;
        return NULL;
    }
 
    int i = 0;
    if(pre[0] != post[length - 1])//在前序和后序遍历序列中找到的根不一样
    {
        *tag = 1;//设置错误
        return NULL;
    }
 
    char Root = pre[0];//根
    char rightRoot = post[length - 2]; //右子树根
    while(pre[i] != rightRoot && i < length)
    {
        i++;//在前序遍历中找到右子树的根,从而分隔左右子树
    }
    if( i == length )
    {
        *tag = 1;//在前序序列没找到右子树的根,错误
        return NULL;
    }
 
    int leftlength = i - 1;//左子树节点个数
    int rightlength = length - i;//右子树节点个数
 
    BitNode * T = (BitNode*)malloc(sizeof(BitNode));
    T->data = Root;
 
    T->lchild = Creat_ProperBiTree(&pre[1], &post[0], leftlength,tag);
    T->rchild = Creat_ProperBiTree(&pre[i], &post[i - 1], rightlength,tag);
    return T;
}

注:文件指针做成全局变量更好,会节省不少行代码,也可以提高代码运行效率。(懒得不想改了)

附上流程图:
在这里插入图片描述

以下是由前序遍历和后序遍历构建二叉树的C语言代码: ```c #include <stdio.h> #include <stdlib.h> struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; }; struct TreeNode* buildTreeHelper(int* preorder, int preStart, int preEnd, int* inorder, int inStart, int inEnd, int* postorder, int postStart, int postEnd) { if (preStart > preEnd || inStart > inEnd || postStart > postEnd) { return NULL; } struct TreeNode* root = (struct TreeNode*)malloc(sizeof(struct TreeNode)); root->val = preorder[preStart]; int inIndex = 0; for (int i = inStart; i <= inEnd; i++) { if (inorder[i] == root->val) { inIndex = i; break; } } int leftTreeSize = inIndex - inStart; int rightTreeSize = inEnd - inIndex; root->left = buildTreeHelper(preorder, preStart + 1, preStart + leftTreeSize, inorder, inStart, inIndex - 1, postorder, postStart, postStart + leftTreeSize - 1); root->right = buildTreeHelper(preorder, preStart + leftTreeSize + 1, preEnd, inorder, inIndex + 1, inEnd, postorder, postStart + leftTreeSize, postEnd - 1); return root; } struct TreeNode* buildTree(int* preorder, int preorderSize, int* inorder, int inorderSize, int* postorder, int postorderSize) { return buildTreeHelper(preorder, 0, preorderSize - 1, inorder, 0, inorderSize - 1, postorder, 0, postorderSize - 1); } void printTree(struct TreeNode* root) { if (root == NULL) { return; } printf("%d ", root->val); printTree(root->left); printTree(root->right); } int main() { int preorder[] = {1, 2, 4, 5, 3, 6, 7}; int inorder[] = {4, 2, 5, 1, 6, 3, 7}; int postorder[] = {4, 5, 2, 6, 7, 3, 1}; int size = sizeof(preorder) / sizeof(preorder[0]); struct TreeNode* root = buildTree(preorder, size, inorder, size, postorder, size); printf("前序遍历结果:"); printTree(root); printf("\n"); return 0; } ``` 这里假设前序遍历为preorder,后序遍历为postorder,中序遍历为inorder。函数buildTreeHelper()用于构建二叉树,其中preStart和preEnd表示当前前序遍历序列的起始和结束位置,inStart和inEnd表示当前中序遍历序列的起始和结束位置,postStart和postEnd表示当前后序遍历序列的起始和结束位置。在函数中,首先根据前序遍历序列的第一个元素创建根节点root,然后在中序遍历序列中查找到root的位置inIndex,进而计算出左子树的大小leftTreeSize和右子树的大小rightTreeSize。接下来,分别递归构建左子树和右子树,并将根节点的左右子树指针指向左右子树的根节点。最后,返回根节点。函数buildTree()是对buildTreeHelper()的包装,传入前序遍历序列、中序遍历序列后序遍历序列的起始位置和大小。函数printTree()用于前序遍历打印二叉树,方便验证结果。主函数中定义了三个遍历序列,通过buildTree()创建二叉树并打印前序遍历结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值