已知先序、中序求后序;已知中序、后序求先序(C++)

先序中序后序的相互求解问题

一、问题描述

我们知道,二叉树有三种深度优先遍历方法:先序中序以及后序,那么,如何已知其中两种遍历序列,求解第三种遍历序列呢。

其实也没大家想得那么美好哈,已知先序、中序可以确定后序,已知中序,后序可以确定先序,但是已知先序和后序是不能确定中序的。究其原因,其实很简单,因为中序可以确定根节点的左孩子是哪块,右孩子是哪块,就是可以确定父子关系嘛。但是如果知道先序和后序的话,举一个例子,看下面的图:


先序为:1 2;后序为:2 1

先序为:1 2;后序为 2 1

所以,其实已知先序和后序时,是不能确定二叉树的,但是如果含有中序序列,那是可以的。

二、解决方案

我们看下如果手算是怎样的、、举个例子哈,先从先序中序开始:

先序:1 2 3 4 5 6

中序:3 2 4 1 6 5

(1)首先,从先序来看,我们知道1是先序的第一个元素,也是这棵二叉树的根节点。

(2)接着,我们找中序里面对应的1的位置,找到了之后,我们发现3 2 4是在1的左边,也就是说这些都是1的左孩子,先不管这些内部复杂的亲子兄弟关系了。6 5是在1的右边,也就是说这些都是1的右孩子。

(3)在先序中找2 3 4的第一个,是2,在中序里面对应的2左边是3,右边是4,分别是它的左右孩子。

(4)在先序中找6 5,发现第一个是5,在中序里面对应的5地左边是6,右边没有,也就是说,5只有一个左孩子,是6。

(5)由此得到的树为:

已知中序和后序的也很类似,就不详述了。

那么,下面介绍用算法实现的步骤是什么,其实就是简单的递归:

(1)确定根,确定左子树,确定右子树。

(2)在左子树中递归。

(3)在右子树中递归。

(4)打印当前根。

这样看上去似乎很简单,下面看代码好了

三、代码实现

(1)已知先序中序求后序

<pre name="code" class="cpp">struct TreeNode{//每一个节点的属性:左节点、右节点、数据
    int data;
    TreeNode* left;
    TreeNode* right;
};
void BinaryTreeFromOrderings(int *inorder,int *preorder,int length)//中序序列,先序序列,中序中需要寻找的字段长度
{
    if(length==0)
        return;

    TreeNode* node=new TreeNode;//新建一个节点,节点的数据为先序的首个元素
    node->data=*preorder;

    int rootIndex;//根节点在中序数组中的下标
    for(rootIndex=0;rootIndex<length;rootIndex++)
        if(inorder[rootIndex]==*preorder)
            break;

    //后序遍历输出结果
    BinaryTreeFromOrderings(inorder,preorder+1,rootIndex);//中序的左边一半长度作为新的需要寻找的字段长度
    BinaryTreeFromOrderings(inorder+rootIndex+1,preorder+rootIndex+1,length-(rootIndex+1));//中序的后面一段长度作为需要寻找的字段长度
    cout<<node->data;
}

 
(2)已知中序后序求先序 

struct TreeNode{//每一个节点的属性:左节点、右节点、数据
    int data;
    TreeNode* left;
    TreeNode* right;
};
void BinaryTreeFromOrderings(int *inorder,int *lastorder,int length)//中序序列,先序序列,中序中需要寻找的字段长度
{
    if(length==0)
        return;
    
    TreeNode* node=new TreeNode;
    node->data=lastorder+length-1;
    
    int rootindex;
    for(rootindex=0;rootindex<length;rootindex++)
        if(inorder[rootindex]==node->data)
            break;
    
    cout<<node->data<<" ";
    BinaryTreeFromOrderings(inorder,lastorder,rootindex);
    BinaryTreeFromOrderings(inorder+rootindex+1,lastorder+rootindex,length-(rootindex+1));
}



可以使用递归的方式来实现先序中序后序,具体实现代码如下: ```java public class Tree { private static class Node { private char value; private Node left; private Node right; public Node(char value) { this.value = value; } } public static String preInToPost(String preOrder, String inOrder) { if (preOrder == null || inOrder == null || preOrder.length() != inOrder.length()) { return null; } Node root = preInToPost(preOrder.toCharArray(), 0, preOrder.length() - 1, inOrder.toCharArray(), 0, inOrder.length() - 1); StringBuilder sb = new StringBuilder(); postOrder(root, sb); return sb.toString(); } private static Node preInToPost(char[] preOrder, int preStart, int preEnd, char[] inOrder, int inStart, int inEnd) { if (preStart > preEnd) { return null; } Node root = new Node(preOrder[preStart]); int index = findIndex(inOrder, inStart, inEnd, preOrder[preStart]); int leftSize = index - inStart; root.left = preInToPost(preOrder, preStart + 1, preStart + leftSize, inOrder, inStart, index - 1); root.right = preInToPost(preOrder, preStart + leftSize + 1, preEnd, inOrder, index + 1, inEnd); return root; } private static void postOrder(Node root, StringBuilder sb) { if (root == null) { return; } postOrder(root.left, sb); postOrder(root.right, sb); sb.append(root.value); } private static int findIndex(char[] arr, int start, int end, char target) { for (int i = start; i <= end; i++) { if (arr[i] == target) { return i; } } return -1; } public static void main(String[] args) { String preOrder = "ABDCEGF"; String inOrder = "DBAEGCF"; String postOrder = preInToPost(preOrder, inOrder); System.out.println(postOrder); // DCBGEFA } } ``` 该代码中使用了一个内部类 `Node` 表示二叉树的节点,`preInToPost` 方法用于递归构建二叉树,`postOrder` 方法用于递归遍历二叉树并输出后序遍历序列,`findIndex` 方法用于查找中序遍历序列中某个元素的位置。最后在 `main` 方法中调用 `preInToPost` 方法并输出结果。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值