由前序(后序)中序构造二叉树

(注:父节点P 左子树L 右子树R)
结论:只有中序遍历+前序遍历 或者 中序遍历+后序遍历能得出树的构造,而前序遍历+后序遍历不能构造出树
原因
以下是任何一棵二叉树的三种遍历结果
先序遍历 P L R
中序遍历 L P R
后序遍历 L R P
构造出一棵树的重点在于分清左右子树,而先序和后序遍历中左右子树的序列是连接在一起的,不能被划分开,只要有中序遍历能将左右子树分开
具体的构造方法
先序遍历+中序遍历
先序遍历 P L R
中序遍历 L P R
先序遍历的第一个节点就是根节点,然后通过根节点可以将中序遍历的结果划分为左右子树,而后可以递归创建左孩子和右孩子。

后序遍历+中序遍历
后序遍历 L R P
中序遍历 L P R
后序遍历的最后一个节点就是根节点,然后通过根节点可以将中序遍历的结果划分为左右子树,而后可以递归创建左孩子和右孩子。

测试实例
(0代表NULL)
第一棵树
这里写图片描述
先序遍历 124783569
中序遍历 748215369
后序遍历 784259631
测试结果一:
这里写图片描述
测试结果二:
这里写图片描述

实现代码:

#include<stdio.h>
#include<stdlib.h>
const int MAX_LENGTH = 100;
struct Node
{
    char data;
    Node* Leftchild;
    Node* Rightchild;
};
int findParent(char parent,char midTraversal[])
{
    int i = 0;
    for (i = 0;; i++)
    {
        if (parent == midTraversal[i])
            break;
    }
    return i;
}

Node* preorder_midorder(char preTraversal[],char midTraversal[],int currentLength)
{
    /*示例
    根节点P    左子树L        右子树R
    先序遍历   P     L      R
    中序遍历   L     P      R
    */
    int parentpos=findParent(preTraversal[0],midTraversal);//根节点在中序遍历中位置
    int leftLength=0, rightLength=0;
    Node* currentRoot = (Node*)malloc(sizeof(Node));
    currentRoot->data = preTraversal[0];//这是当前的该子树的根节点
    currentRoot->Leftchild = NULL;
    currentRoot->Rightchild = NULL;
    if (currentLength != 1)//说明这不是叶子节点,至少有一棵子树
    {
        //递归创建左子树
        if (parentpos == 0)//中序遍历的结果中父节点在首位,说明此时只有右子树,没有左子树
            currentRoot->Leftchild = NULL;
        else
        {
            leftLength=parentpos;          //左子树遍历序列的长度可以有中序遍历中根节点的位置确定
            char leftMid[MAX_LENGTH];      //左子树的中序遍历结果
            char leftPre[MAX_LENGTH];      //左子树遍先序遍历结果
            for (int i = 0; i < leftLength; i++)
            {
                leftPre[i] = preTraversal[i+1];
                leftMid[i] = midTraversal[i];  
            }
            currentRoot->Leftchild = preorder_midorder(leftPre,leftMid,leftLength);
        }
        //递归创建右子树
        if (parentpos == currentLength - 1)//中序遍历的结果中父节点在末位,说明此时只有左子树,没有右子树
            currentRoot->Rightchild = NULL;
        else
        {
            rightLength = currentLength - (parentpos+1);//右子树遍历序列的长度可以有中序遍历中根节点的位置确定
            char rightMid[MAX_LENGTH];      //右子树中序遍历结果
            char rightPre[MAX_LENGTH];      //右子树先序遍历结果
            for (int i = 0; i < rightLength; i++)
            {
                rightPre[i] = preTraversal[i+1+leftLength];
                rightMid[i] = midTraversal[i + parentpos+1];
            }
            currentRoot->Rightchild = preorder_midorder(rightPre, rightMid, rightLength);
        }
    }
    return currentRoot;//结束递归,返回当前的根节点
}
Node* postorder_midorder(char postTraversal[], char midTraversal[], int currentLength)
{
    /*示例
    根节点P    左子树L        右子树R
    中序遍历   L     P      R
    后序遍历   L     R      P
    */
    int parentpos = findParent(postTraversal[currentLength-1], midTraversal);//根节点在中序遍历中位置
    int leftLength = 0, rightLength = 0;
    Node* currentRoot = (Node*)malloc(sizeof(Node));
    currentRoot->data = postTraversal[currentLength - 1];
    currentRoot->Leftchild = NULL;
    currentRoot->Rightchild = NULL;

    if (currentLength != 1)//说明这不是叶子节点,至少有一棵子树
    {
        //递归创建左子树
        if (parentpos == 0)//中序遍历的结果中父节点在首位,说明此时只有右子树,没有左子树
            currentRoot->Leftchild = NULL;
        else
        {
            leftLength = parentpos;          //左子树遍历序列的长度可以有中序遍历中根节点的位置确定
            char leftMid[MAX_LENGTH];        //左子树的中序遍历结果
            char leftPost[MAX_LENGTH];       //左子树遍后序遍历结果
            for (int i = 0; i < leftLength; i++)
            {
                leftPost[i] = postTraversal[i];//复制左子树后序遍历子序列
                leftMid[i] = midTraversal[i];  //复制左子树中序遍历子序列
            }
            currentRoot->Leftchild = postorder_midorder(leftPost, leftMid, leftLength);
        }
        //递归创建右子树
        if (parentpos == currentLength - 1)//中序遍历的结果中父节点在末位,说明此时只有左子树,没有右子树
            currentRoot->Rightchild = NULL;
        else
        {
            rightLength = currentLength - (parentpos + 1);//右子树遍历序列的长度可以有中序遍历中根节点的位置确定
            char rightMid[MAX_LENGTH];  //右子树中序遍历结果
            char rightPost[MAX_LENGTH]; //右子树先序遍历结果
            for (int i = 0; i < rightLength; i++)
            {
                rightPost[i] = postTraversal[i + leftLength];
                rightMid[i] = midTraversal[i + parentpos + 1];
            }
            currentRoot->Rightchild = postorder_midorder(rightPost, rightMid, rightLength);
        }
    }
    return currentRoot;
}
void pre(Node* root)
{
    printf("%c ",root->data);
    if (root->Leftchild!=NULL)
        pre(root->Leftchild);
    if (root->Rightchild!=NULL)
        pre(root->Rightchild);
}
void post(Node* root)
{
    if (root->Leftchild != NULL)
        post(root->Leftchild);
    if (root->Rightchild != NULL)
        post(root->Rightchild);
    printf("%c ",root->data);
}
int main()
{
    int length,cases;
    Node *root = (Node*)malloc(sizeof(Node));
    char preTraversal[MAX_LENGTH],midTraversal[MAX_LENGTH],postTraversal[MAX_LENGTH];
    printf("选择类型:1、先序中序找后序.  2、后序中序找先序:");
    scanf("%d",&cases);
    if (cases == 1){
        printf("输入先序遍历的结果:");
        scanf("%s", preTraversal);
        printf("输入中序遍历的结果:");
        scanf("%s", midTraversal);
        printf("输入遍历结果的长度:");
        scanf("%d", &length);
        root = preorder_midorder(preTraversal, midTraversal, length);
        printf("后序遍历的结果为:");
        post(root);
    }
    else if (cases == 2)
    {
        printf("输入后序遍历的结果:");
        scanf("%s", postTraversal);
        printf("输入中序遍历的结果:");
        scanf("%s", midTraversal);
        printf("输入遍历结果的长度:");
        scanf("%d", &length);
        root = postorder_midorder(postTraversal, midTraversal, length);
        printf("先序遍历的结果为:");
        pre(root);
    }
    printf("\n");
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值