已知二叉树前序和中序,求二叉树。

如题,给出二叉树的前序遍历和中序遍历,怎么还原二叉树。

  假如一个二叉树的前序遍历为:12453,中序遍历为:42513。由于这颗二叉树比较简单,可以用 凑 的方法很容易凑出符合题意的二叉树(没有写这篇文章之前,我都是用这种笨方法的..尴尬)。

即如图:

那么有没有一个标准的方法来推导呢?当然是有的!

我们来分析一下这棵树的前序和中序。

  先看前序:12453,第一个字符“1”肯定是整棵树root节点,这不用解释。至于第二个字符以及往后的字符就没有什么可用的信息了。

  再看中序:42513,前序中只有“1”这个节点有用,我们在中序中找到“1”的位置,然后再对照上面的图,会发现在“1”左边的所有字符是“1”这个节点的左子树,“1”右边的所有字符是“1”这个节点的右子树。

既然知道了“1”这个节点的左右子树,那么我们可以先把“1”这个节点忽略掉,再分别求“1”这个节点 左右子树 的root节点。

先求“1”的左子树的root节点:

  先找到“1”的左子树的中序:42513 --> 425,然而并没有什么有用的信息。

  再找到“1”的左子树的前序:12453 --> 245,我们刚才说过前序遍历的第一个字符肯定是它所在的树的root节点。即“2”是  “1”的左子树245的  root节点。

接下来求“1”的右子树的root节点:

  先找到“1”的右子树的中序:42513 --> 3,只有一个节点。

  再找到“1”的右子树的前序:12453 --> 3,只有一个节点,那么“3”是“1”的右子树的root节点。

知道了“1”和“2”是root节点,再把“2”忽略掉,分别求“2”这个节点的 左右子树的 root节点。

求“2”的左子树的root节点:

  “2”的左子树的中序:425 --> 4,“4”为其左子树。

  “2”的左子树的前序:245 --> 4,可以确认“4”为当前子树的root节点。

求“2”的右子树的root节点:

  “2”的右子树的中序:425 --> 5,“5”为其右子树。

  “2”的右子树的前序:245 --> 5,可以确认“5”为当前子树的root节点。

看到这里你应该会明白:中序用来找某个节点的左右子树,前序用来找某个子树的root节点。其中,当某个子树长度为0时,root=NULL,返回。

根据这个规律:我们可以递归地找到所有子树的root节点,那么这棵树各个节点的相对位置也就确认了。

代码实现方法:

#include <iostream>
#include <cstring>

using namespace std;

//先定义二叉树节点结构体
typedef struct Bitree
{
    char data;
    struct Bitree *lchild;
    struct Bitree *rchild;
}BiTree;

//第一种建树方式,传入节点指针  这里的len参数指的是mid数组的结尾下标。当len为0时,代表有一个节点。
void buildTree(BiTree *&node,char *pre,char *mid,int len)
{
    if(len<0)      //当结尾下标<0时,没有子树
    {
        node=NULL;
        return;
    }
    for(int i=0;i<=len;i++)   //遍历mid数组找到子树的root节点 并为其分配空间,赋值。
    {
        if(pre[0]==mid[i])    //中序遍历中找到root节点(前序第一个字符就是root节点)
        {
            node=new BiTree;
            node->data=pre[0];
            buildTree(node->lchild,pre+1,mid,i-1);    //递归地找左子树的root节点
            buildTree(node->rchild,pre+i+1,mid+i+1,len-i-1);  //递归地找右子树的root节点
        }
    }
}
//第二种建树方法,函数返回节点指针
BiTree* buildTree2(char *pre,char *mid,int len)
{
    BiTree *node;
    for(int i=0;i<=len;i++)
    {
        if(pre[0]==mid[i])
        {
            node=new BiTree;
            node->data=pre[0];
            node->lchild=buildTree2(pre+1,mid,i-1);
            node->rchild=buildTree2(pre+i+1,mid+i+1,len-i-1);
            return node;
        }
    }
    return NULL;
}
void preOrder(BiTree *node)  //前序遍历输出二叉树
{
    if(node)
    {
        cout<<node->data;
        preOrder(node->lchild);
        preOrder(node->rchild);
    }
}
void midOrder(BiTree *node)   //中序遍历输出二叉树
{
    if(node)
    {
        preOrder(node->lchild);
        cout<<node->data;
        preOrder(node->rchild);
    }
}
int main()
{
    char pre[]="12453";  //前序遍历
    char mid[]="42513";  //中序遍历
    BiTree *root;
    //buildTree(root,pre,mid,4);
    root=buildTree2(pre,mid,4);
    preOrder(root);
    cout<<endl;
    midOrder(root);
    return 0;
}
时间: 2024-10-10 06:55:53

已知二叉树前序和中序,求二叉树。的相关文章

java 根据二叉树前序 ,中序求后续

在一棵二叉树总,前序遍历结果为:ABDGCEFH,中序遍历结果为:DGBAECHF,求后序遍历结果. 我们知道: 前序遍历方式为:根节点->左子树->右子树 中序遍历方式为:左子树->根节点->右子树 后序遍历方式为:左子树->右子树->根节点 从这里可以看出,前序遍历的第一个值就是根节点,然后再中序遍历中找到这个值,那么这个值的左边部分即为当前二叉树的左子树部分前序遍历结果,这个值的右边部分即为当前二叉树的右子树部分前序遍历结果.因此,通过这个分析,可以恢复这棵二叉树

construct-binary-tree-from-preorder-and-inorder-traversal——前序和中序求二叉树

Given preorder and inorder traversal of a tree, construct the binary tree. Note:  You may assume that duplicates do not exist in the tree. 1 /** 2 * Definition for binary tree 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right

【基础备忘】 二叉树前序、中序、后序遍历相互求法

转自:http://www.cnblogs.com/fzhe/archive/2013/01/07/2849040.html 今天来总结下二叉树前序.中序.后序遍历相互求法,即如果知道两个的遍历,如何求第三种遍历方法,比较笨的方法是画出来二叉树,然后根据各种遍历不同的特性来求,也可以编程求出,下面我们分别说明. 首先,我们看看前序.中序.后序遍历的特性: 前序遍历:     1.访问根节点     2.前序遍历左子树     3.前序遍历右子树 中序遍历:     1.中序遍历左子树     2

二叉树前序、中序、后序遍历相互求法

今天来总结下二叉树前序.中序.后序遍历相互求法,即如果知道两个的遍历,如何求第三种遍历方法,比较笨的方法是画出来二叉树,然后根据各种遍历不同的特性来求,也可以编程求出,下面我们分别说明. 首先,我们看看前序.中序.后序遍历的特性: 前序遍历:     1.访问根节点     2.前序遍历左子树     3.前序遍历右子树 中序遍历:     1.中序遍历左子树     2.访问根节点     3.中序遍历右子树 后序遍历:     1.后序遍历左子树     2.后序遍历右子树     3.访问

【转】二叉树前序、中序、后序遍历相互求法

今天来总结下二叉树前序.中序.后序遍历相互求法,即如果知道两个的遍历,如何求第三种遍历方法,比较笨的方法是画出来二叉树,然后根据各种遍历不同的特性来求,也可以编程求出,下面我们分别说明. 首先,我们看看前序.中序.后序遍历的特性: 前序遍历:     1.访问根节点     2.前序遍历左子树     3.前序遍历右子树 中序遍历:     1.中序遍历左子树     2.访问根节点     3.中序遍历右子树 后序遍历:     1.后序遍历左子树     2.后序遍历右子树     3.访问

二叉树前序、中序、后序遍历非递归写法的透彻解析

前言 在前两篇文章二叉树和二叉搜索树中已经涉及到了二叉树的三种遍历.递归写法,只要理解思想,几行代码.可是非递归写法却很不容易.这里特地总结下,透彻解析它们的非递归写法.其中,中序遍历的非递归写法最简单,后序遍历最难.我们的讨论基础是这样的: //Binary Tree Node typedef struct node { int data; struct node* lchild; //左孩子 struct node* rchild; //右孩子 }BTNode; 首先,有一点是明确的:非递归

根据前序和中序重建二叉树

注意:1.仅根据前序和后序无法构建唯一的二叉树:2.二叉树前序遍历,第一个数字总是树的根节点的值:3.中序遍历中,根节点的值在序列的中间,左子树的值子在根节点的值的左边,右字树的值在根节点的值的右边:4.思路:递归 #include <iostream> #include <stdlib.h> using namespace std; struct Node{ int value; Node* left; Node* right; }; Node* ConstructCore(in

二叉树前序、中序和后序的遍历方法(递归、用栈和使用线索化)

在2^k*2^k个方格组成的棋盘中,有一个方格被占用,用下图的4种L型骨牌覆盖所有棋盘上的其余所有方格,不能重叠. 代码如下: def chess(tr,tc,pr,pc,size): global mark global table mark+=1 count=mark if size==1: return half=size//2 if pr<tr+half and pc<tc+half: chess(tr,tc,pr,pc,half) else: table[tr+half-1][tc+

关于二叉树的问题1-已知前序,中序求后序遍历

对于一棵二叉树而言,可以由其前序和中序或者中序和后序的遍历序列,确定一棵二叉树. 那么对于已知前序和中序序列,求后序序列也就是先还原二叉树,然后对其进行后序遍历即可. 二叉树结点的结构定义如下: struct TreeNode { char value; TreeNode *leftChild; TreeNode *rightChild; }; 实现代码如下: #include <stdio.h> #include <string.h> #include <stdlib.h&