关于二叉树的前序、中序、后序问题

本文详细解析了如何根据二叉树的前序、中序或后序遍历序列来求解其他两种遍历序列。介绍了已知前序和中序遍历构造后序遍历的方法,强调了构造二叉树的关键步骤,并指出已知前序和后序遍历无法唯一确定中序遍历。同时,概述了已知中序和后序遍历求前序遍历的类似思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于二叉树的前序、中序、后序问题

前序遍历:
1. 访问根节点
2. 前序遍历左子树
3. 前序遍历右子树

中序遍历:
1. 中序遍历左子树
2. 访问根节点
3. 中序遍历右子树

后序遍历:
1. 后序遍历左子树
2. 后序遍历右子树
3. 访问根节点

写到这里可能还是有很多人不理解,接下来我写一点程序来帮助大家理解

public class Node{
    Node left;
    Node right;
    char value;
}

这是一个二叉树最基本的结点类,而关于二叉树的遍历其实特别的简单

public static void postTrav(Node root){
    //遍历左子树
    if(root.left!=null)
        postTrav(root.left);
    //遍历右子树
    if(root.right!=null)
        postTrav(root.right);
    //输出本节点
    System.out.println(root.value);
}

这便是二叉树的后序遍历,看了后是不是焕然大悟,只要将其中的if语句与输出语句进行调整,就能很快的写出二叉树的前序中序和后序遍历。

在笔试或面试过程中有时会被问到已知树的前序和中序求后序这类的问题。(其实就是我前段时间笔试遇到了~才去认真看了下这些知识),下面对其进行介绍说明,最主要的思想是递归。

1. 已知前序和中序,求后序。

上面的程序中写了遍历树的方法,可以很快求出二叉树的前序中序后序,直接用不就好了么?是的!前提是我要首先要知道这棵树是什么样的,因此我们需要通过给出的前序和中序,构造出这个完整的树。

怎么构造这棵树呢?下面我们举个例子,假设一棵树

前序遍历: GDAFEMHZ

中序遍历: ADEFGHMZ

第一步,根据前序遍历的特点,我们知道根结点为G

第二步,观察中序遍历ADEFGHMZ。其中root节点G左侧的ADEF必然是root的左子树,G右侧的HMZ必然是root的右子树。

第三步,观察左子树ADEF,左子树的中的根节点必然是大树的root的leftchild。在前序遍历中,大树的root的leftchild位于root之后,所以左子树的根节点为D。

第四步,同样的道理,root的右子树节点HMZ中的根节点也可以通过前序遍历求得。在前序遍历中,一定是先把root和root的所有左子树节点遍历完之后才会遍历右子树,并且遍历的左子树的第一个节点就是左子树的根节点。同理,遍历的右子树的第一个节点就是右子树的根节点。

第五步,观察发现,上面的过程是递归的。先找到当前树的根节点,然后划分为左子树,右子树,然后进入左子树重复上面的过程,然后进入右子树重复上面的过程。

下面用代码实现构树:

private static void buildBinaryTree(String pre, String mid, Node root) {
    int len=pre.length();
    if(len==0)return;
    int pos=0;
    //计算出前序第一位,即根结点在中序的第几位
    for(int i=0;i<mid.length();i++){
    if(mid.charAt(i)==pre.charAt(0)){
        pos=i;
        break;
        }
    }
    //根结点的值即为前序第一位的值
    root.value=pre.charAt(0);
    if(pos!=0){//当前节点的左子树是存在的
        Node left=new Node();
        root.left=left;
        //求出左子树的前序和中序
        String left_pre=pre.substring(1,pos+1);
        String left_mid=mid.substring(0,pos);
        //递归建立左子树
        buildBinaryTree(left_pre, left_mid, left);
    }
    if(pos!=len-1){//当前节点的右子树是存在的
        Node right=new Node();
        root.right=right;
        //求出右子树的前序和中序
        String right_pre=pre.substring(pos+1,len);
        String right_mid=mid.substring(pos+1,len);
        //递归建立右子树
        buildBinaryTree(right_pre, right_mid, right);
    }
}

2. 已知前序和后序,求中序。

此种情况是不可唯一确定解的,只能确定根节点,而对于左右子树的组成不确定。

3. 已知中序和后序,求前序。

其过程与已知前序和中序求后序类似,这里不在重复。

下面给出完整的java代码:

public class Main{
    public static class Node{
        Node left;
        Node right;
        char elem;
    }
    public static void postTrav(Node root){
        //遍历左子树
        if(root.left!=null)
            postTrav(root.left);
        //遍历右子树
        if(root.right!=null)
            postTrav(root.right);
        //输出本节点
        System.out.println(root.elem);
    }
    public static void main(String[] args){
        String pre="GDAFEMHZ";
        String in="ADEFGHMZ";
        Node root=new Node();
        buildBinaryTree(pre,in,root);
        postTrav(root);
    }
    private static void buildBinaryTree(String pre, String in, Node root) {
        // TODO Auto-generated method stub
        int len=pre.length();
        if(len==0)return;
        int pos=0;
        for(int i=0;i<in.length();i++){
            if(in.charAt(i)==pre.charAt(0)){
                pos=i;
                break;
            }
        }
        root.elem=pre.charAt(0);
        if(pos!=0){//当前节点的左子树是存在的
            Node left=new Node();
            root.left=left;
            String left_pre=pre.substring(1,pos+1);
            String left_in=in.substring(0,pos);
            buildBinaryTree(left_pre, left_in, left);
        }
        if(pos!=len-1){//当前节点的右子树是存在的
            Node right=new Node();
            root.right=right;
            //right.elem=pre.charAt(pos+1);
            String right_pre=pre.substring(pos+1,len);
            String right_in=in.substring(pos+1,len);
            buildBinaryTree(right_pre, right_in, right);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值