您的位置:首页 > 其它

给定二叉树的前序遍历结果,输出所有可能的中序遍历的结果

2018-03-30 16:36 483 查看
题目如下:给出一个二叉树的前序遍历,输出这个树所有可能的中序遍历(有时也会可能会是后序遍历)
对应于一棵二叉树的前序遍历,我们知道,前序遍历的第一个节点,一定是根节点。所以,我们可以很容易的找出根节点,剩下的部分呢,是左子树和右子树节点在一起了,本题的难点就在于,你如何去将前序遍历的结果中除去根节点部分的其余节点分为左右子树的节点。暴力一些就是慢慢拆。以前序遍历{1,2,3}为例。


因为节点较少,分析起来也很直观,所以我们可以分为以上几种情况,对于case1和case3,我们可以看出,case1中的2,3又可以存在两种不同的情况,case3中的左子树同理。可以分为以下5中情况。



这时候可以直接上代码了吧。package oj;

import java.util.ArrayList;
import java.util.List;

public class Solution2 {
public static void main(String[] args) {
int []preorder= {1,2,3,4,5};
List<BinaryTree> trees=GetAllTrees(preorder, 0, preorder.length-1);
//System.out.println(trees);
for(BinaryTree tr:trees)
{
tr.PrintInOrder();
}

}
/*
* 我们考虑一下上面的思路。
* 首先我们需要先找到整棵二叉树的根节点,然后将剩下的节点进行划分,
* 划分的方法无非就是a个节点作为左子树,n-a-1个节点作为右子树。
* 我们选取一个ArrayList来存储所有可能的结构,原因是这一数据结构
* 方便我们来 append/remove
*/
static List<BinaryTree> GetAllTrees(int[]preorder, int start,int end){
//resultTree用来接收所有的可能的结果,并返回
List<BinaryTree>resultTree=new ArrayList<>();
if(start>end||start<0||end>=preorder.length)
{
resultTree.add(null);
return resultTree;
}
if(start==end)
{
//前序遍历只给定一个节点的情况,这时直接将其添加到resultTree中,返回即可
resultTree.add(new BinaryTree(preorder[start]));
return resultTree;
}
/*好吧,最头疼的代码要开始了
* 首先,我们的左右子树节点的个数是从0~n-1的,所以我们可以记左节点个数为i,右节点的个数为n-1-i
*/
for(int i=-1;i< end-start;i++) {
//注意i的值是从-1开始的,意味着左子树可以为空,左子树时start+1+i的部分,
//右子树则从start+1+i+1开始。一直到end结束。就这样递归着就可以将左右子树根据i值得不同划分好。
List<BinaryTree> leftChlidren=GetAllTrees(preorder, start+1, start+1+i);
List<BinaryTree> rightChildren=GetAllTrees(preorder, start+1+i+1, end);
//这时候根据i的值划分好左右子树,需要我们分配相应的树形结构
for(BinaryTree leftpart:leftChlidren) {
for(BinaryTree rightpart:rightChildren) {
BinaryTree tempRoot=new BinaryTree(preorder[start]);
tempRoot.left=leftpart;
tempRoot.right=rightpart;
resultTree.add(tempRoot);
}
}
}

return resultTree;
}
}
//首先,我们先定义我们的简单二叉树结构
class BinaryTree{
int val;
BinaryTree left;
BinaryTree right;
public BinaryTree(int k)
{
this.val=k;
}
//同样我们需要输出中序遍历的结果
public void PrintInOrder()
{
InOrderTraversal(this);
System.out.println();//输出换行
}
private void InOrderTraversal(BinaryTree tree) {
if(tree==null)return;
InOrderTraversal(tree.left);
System.out.print(tree.val);
InOrderTraversal(tree.right);
}
}
另一个问题如下:
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。(剑指offer第六题)

借用他的思路吧,反正我也是这么想的



根据前序遍历的特点,我们知道根结点为1
观察中序遍历。其中root节点G左侧的472必然是root的左子树,G右侧的5386必然是root的右子树。
观察左子树472,左子树的中的根节点必然是大树的root的leftchild。在前序遍历中,大树的root的leftchild位于root之后,所以左子树的根节点为2。
同样的道理,root的右子树节点5386中的根节点也可以通过前序遍历求得。在前序遍历中,一定是先把root和root的所有左子树节点遍历完之后才会遍历右子树,并且遍历的左子树的第一个节点就是左子树的根节点。同理,遍历的右子树的第一个节点就是右子树的根节点。
观察发现,上面的过程是递归的。先找到当前树的根节点,然后划分为左子树,右子树,然后进入左子树重复上面的过程,然后进入右子树重复上面的过程。最后就可以还原一棵树了。
该步递归的过程可以简洁表达如下:
确定根,确定左子树,确定右子树。
在左子树中递归。
在右子树中递归。
打印当前根。


public class Solution {
// 给定前序和中序遍历的结果
public TreeNode reConstructBinaryTree(int[] pre, int[] in) {
TreeNode root = reConstructBinaryTree(pre, 0, pre.length - 1, in, 0, in.length - 1);
return root;
}

private TreeNode reConstructBinaryTree(int[] pre, int startPre, int endPre, int[] in, int startIn, int endIn) {

if (startPre > endPre || startIn > endIn)
return null;
TreeNode root = new TreeNode(pre[startPre]);

for (int i = startIn; i <= endIn; i++) {
if (in[i] == pre[startPre]) {// 从这里开始划分好二叉树中的左子树和右子树
// 前序中,从startPre+1位置开始,到startPre+(i-startIn)的部分是左子树。
root.left = reConstructBinaryTree(pre, startPre + 1, startPre + i - stratIn, in, startIn, i - 1);
root.right = reConstructBinaryTree(pre, startPre + i - startIn + 1, endPre, in, i + 1, endIn);

break;
}
}

return root;
}
}
溜了溜了,一下午写了两道题解。没干啥正事,啊啊啊啊啊好慌啊
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐