利用后序和先序遍历恢复二叉树

利用后序和先序遍历恢复二叉树

??利用后序和中序遍历可以将二叉树还原出来,以便于进行其他树的操作。在这里我们还原出二叉树之后进行先序遍历来求得先序遍历的结果,我们约定还原树的函数叫做RestoreTree()。

过程

后序遍历实例:C B E H G I F D A

中序遍历实例:B C A E D G H F I

中序遍历开始位置,结束位置记做z1,z2,后序的记为h1,h2

  1. 新建一颗空树,左右孩子置空
  2. 拿到后序遍历的最后一个结点,其位置为z2,将该值存入树的数据域
  3. 在中序遍历的序列中以遍历的方式找到最后一个结点的位置,记为i
  4. 如果i!=z1,说明以该结点为根结点的树有左子树,以递归的方式,调用当前函数恢复左子树
  5. 如果i!=z2,说明以该结点为根结点的树有右子树,,以递归的方式调用当前函数恢复右子树
  6. 返回树的根结点值

需要注意的地方

??在恢复左右子树的时候,其位置需要算出来,即h1,h2和z1,z2的值需要重新计算,并在更新之后传递给RestoreTree()函数。以构建左子树为例,左子树的首元素下标为z1,最后一个元素下标为i-1,对应的h1的值为h1,h2的值为h1+(i-z1-1),也就是h1当前的位置向前移动i-z1-1个长度。

代码实现

以实现之前提到的字母序列为例

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

typedef struct Bitree{
    char data;
    struct Bitree* lchild;
    struct Bitree* rchild;
}*bitree,bitnode;
bitree Createtree(void);
bitree Restoretree(int h1,int h2,int z1,int z2);
void Preorder(bitree bt);
char in[50],post[50];
int main(void)
{
    int n;
    scanf("%d",&n);
    getchar();
    //getchar()用于清除回车
    for(int i = 0;i < n;i++)
        scanf("%c",&post[i]);
    getchar();
    for(int i = 0;i < n;i++)
        scanf("%c",&in[i]);
    bitree b = Restoretree(0,n-1,0,n-1);
    Preorder(b);
    printf("\n");
    return 0;
}

bitree Createtree(void)
{
    bitree bt = (bitree)malloc(sizeof(bitnode));
    bt->lchild = bt->rchild = NULL;
    return bt;
}
bitree Restoretree(int h1,int h2,int z1,int z2)
{
    bitree bt = Createtree();
    bt->data = post[h2];
    for(int i = z1;i <= z2;i++)
    {
        if(in[i]==post[h2])
        {
            if(i!=z1)//存在左子树,构建左子树
                bt->lchild = Restoretree(h1,h1+i-z1-1,z1,i-1);
            if(i!=z2)//存在右子树,构建右子树
                bt->rchild = Restoretree(h2-z2+i,h2-1,i+1,z2);
            break;//找到以后跳出遍历
        }
    }
    return bt;
}
void Preorder(bitree bt)
{
    if(!bt)
        return;
    printf("%c ",bt->data);
    Preorder(bt->lchild);
    Preorder(bt->rchild);
}

??由于代码在恢复树的时候先恢复的根结点,然后访问的左右子树,因此,恢复的过程也相当于一个先根遍历的过程.如果只想求先根遍历,可以不建树.我们可以删掉先根遍历的函数,同时简化一些其他的语句.修改后的代码如下:

#include<stdio.h>
typedef struct Bitree{
    char data;
    struct Bitree* lchild;
    struct Bitree* rchild;
}*bitree,bitnode;
void Restoretree(int h1,int h2,int z1,int z2);
char in[50],post[50];
int main(void)
{
    int n;
    scanf("%d",&n);
    getchar();
    for(int i = 0;i < n;i++)
        scanf("%c",&post[i]);
    getchar();
    for(int i = 0;i < n;i++)
        scanf("%c",&in[i]);
    Restoretree(0,n-1,0,n-1);
    printf("\n");
    return 0;
}

void Restoretree(int h1,int h2,int z1,int z2)
{
    printf("%c ",post[h2]);
    for(int i = z1;i <= z2;i++)
    {
        if(in[i]==post[h2])
        {
            if(i!=z1)//存在左子树,访问左子树
                Restoretree(h1,h1+i-z1-1,z1,i-1);
            if(i!=z2)//存在右子树,访问右子树
                Restoretree(h2-z2+i,h2-1,i+1,z2);
            break;//找到以后跳出遍历
        }
    }
}

两段代码得到的结果是一样的,以下是样例输入:

9
CBEHGIFDA
BCAEDGHFI

以下是输出:

A B C D E F G H I 

代码拓展

??在这里补充一段利用先序遍历和中序遍历来还原二叉树并进行后序遍历的代码。

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

typedef struct BiTree{
    int data;
    struct BiTree* lchild;
    struct BiTree* rchild;
}bitnode,*bitree;
void Postorder(bitree bt);
bitree RestoreTree(char* pre,char* in,int q1,int q2,int z1,int z2);

int main()
{
    char pre[10] = {"DBACEGF"},in[10] = {"ABCDEFG"};
    bitree bt= RestoreTree(pre,in,0,6,0,6);
    Postorder(bt);
    return 0;
}
bitree RestoreTree(char* pre,char* in,int q1,int q2,int z1,int z2)
{
    bitree bt = (bitree)malloc(sizeof(bitnode));
    bt->lchild = bt->rchild = NULL;
    bt->data = pre[q1];
    for(int i = z1;i<=z2;i++)
    {
        if(in[i]==pre[q1])
        {
            if(i!=z1)
                bt->lchild = RestoreTree(pre,in,q1+1,q1+i-z1,z1,i-1);
            if(i!=z2)
                bt->rchild = RestoreTree(pre,in,q1+i-z1+1,z2,i+1,z2);
            break;
        }
    }
    return bt;
}
void Postorder(bitree bt)
{
    if(bt->lchild!=NULL)
        Postorder(bt->lchild);
    if(bt->rchild)
        Postorder(bt->rchild);
    printf("%c",bt->data);
}

??代码和之前一样可以简化,简化以后,不需要建树,也可以进行后序遍历。

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

typedef struct BiTree{
    int data;
    struct BiTree* lchild;
    struct BiTree* rchild;
}bitnode,*bitree;
bitree RestoreTree(char* pre,char* in,int q1,int q2,int z1,int z2);

int main()
{
    char pre[10] = {"DBACEGF"},in[10] = {"ABCDEFG"};
    RestoreTree(pre,in,0,6,0,6);
    return 0;
}
bitree RestoreTree(char* pre,char* in,int q1,int q2,int z1,int z2)
{
    for(int i = z1;i<=z2;i++)
    {
        if(in[i]==pre[q1])
        {
            if(i!=z1)
                RestoreTree(pre,in,q1+1,q1+i-z1,z1,i-1);
            if(i!=z2)
                RestoreTree(pre,in,q1+i-z1+1,z2,i+1,z2);
            break;
        }
    }
    printf("%c",pre[q1]);
}

原文地址:https://www.cnblogs.com/kevinbruce656/p/10027802.html

时间: 2024-08-30 00:03:22

利用后序和先序遍历恢复二叉树的相关文章

中序遍历 后序遍历 恢复二叉树

中序遍历:dbeafc 后序遍历:debfca #include <stdio.h> #include <stdlib.h> #include <string.h> void RestoreTree(char *in,char *post,int len ,int treeLen,char* out, int index) { if(index>=treeLen) return; out[index] = post[len-1]; int i = 0; for(;

Construct Binary Tree from Inorder and Postorder Traversal ——通过中序、后序遍历得到二叉树

题意:根据二叉树的中序遍历和后序遍历恢复二叉树. 解题思路:看到树首先想到要用递归来解题.以这道题为例:如果一颗二叉树为{1,2,3,4,5,6,7},则中序遍历为{4,2,5,1,6,3,7},后序遍历为{4,5,2,6,7,3,1},我们可以反推回去.由于后序遍历的最后一个节点就是树的根.也就是root=1,然后我们在中序遍历中搜索1,可以看到中序遍历的第四个数是1,也就是root.根据中序遍历的定义,1左边的数{4,2,5}就是左子树的中序遍历,1右边的数{6,3,7}就是右子树的中序遍历

恢复二叉树

二叉树的遍历方式有,前序遍历.中序遍历.后序遍历.层序遍历. 恢复二叉树的方式中,一定要有中序遍历.如:可以根据 前序+中序.后序+中序,对二叉树进行恢复.若层序遍历中,对于节点为空的节点予以标识为null,则可以只根据层序遍历恢复出二叉树. 1.前序+中序恢复二叉树: 2.后序+中序恢复二叉树: 3.带空节点标识的层序遍历恢复二叉树: 原文地址:https://www.cnblogs.com/guoyu1/p/12389375.html

先序遍历和后序遍历构建二叉树

递归的方法利用先序遍历和中序遍历构建二叉树,同样也可以利用到中序遍历和后序遍历构建二叉树. //利用先序遍历和中序遍历构建二叉树 TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) { TreeNode *root=NULL; if(preorder.size()==0||inorder.size()==0||preorder.size()!=inorder.size()) return

二叉树高度,以及栈实现二叉树的先序,中序,后序遍历的非递归操作

求解二叉树的高度 树是递归定义的,所以用递归算法去求一棵二叉树的高度很方便. #include <iostream> #include <cstdio> using namespace std; struct Node { char data; Node *lchild; Node *rchild; }; void High(Node *T, int &h) { if (T == NULL) h = 0; else { int left_h; High(T->lchi

[Leetcode] Construct binary tree from inorder and postorder travesal 利用中序和后续遍历构造二叉树

Given inorder and postorder traversal of a tree, construct the binary tree. Note:  You may assume that duplicates do not exist in the tree. 利用中序和后序遍历构造二叉树,要注意到后序遍历的最后一个元素是二叉树的根节点,而中序遍历中,根节点前面为左子树节点后面为右子树的节点.例如二叉树:{1,2,3,4,5,6,#}的后序遍历为4->5->2->6-&

[二叉树建树]1119. Pre- and Post-order Traversals (30) (前序和后序遍历建立二叉树)

1119. Pre- and Post-order Traversals (30) Suppose that all the keys in a binary tree are distinct positive integers. A unique binary tree can be determined by a given pair of postorder and inorder traversal sequences, or preorder and inorder traversa

已知二叉树的前序遍历、中序遍历或者中序遍历、后序遍历求二叉树结构的算法

二叉树中的前序遍历是先访问根结点,再访问左子树,右子树. 中序遍历是先访问左子树,再是根结点,最后是右子树. 后序遍历是先访问左子树,再是右子树,最后是根结点. 算法思路是先根据前序遍历的第一个结点或者后序遍历的最后一个结点,查找对应在中序遍历中的位置,就可以确定左子树包含的元素和右子树包含的元素,最后通过递归来实现就可以了. 二叉树的表示形式为 //二叉树的结构表示为 class TreeNode { int val; TreeNode left; TreeNode right; TreeNo

2015-03-15---二叉树递归(非递归)实现先序、中序、后序遍历(附代码)

今天说好的不碰代码的,后来还是没忍住,学了学数据结构和算法,就先讲讲先序中序和后序遍历吧,我还写了代码,一套递归方式实现遍历二叉树,还有两套非递归方式遍历二叉树, 从简单的开始,因为二叉树的所有操作都是要求在能够遍历的基础上啊. 学过数据结构的肯定都明白遍历顺序, 先序遍历就是先自己,然后左子树,然后右子树, 中序遍历就是先左子树,然后自己,然后右子树 后序遍历就是先左子树,然后右子树,然后自己 比如上图这个很简单的二叉树: 先序遍历:1 2 4 5 3 6 7 中序遍历:4 2 5 1 6 3