Tree(利用中序和后序还原二叉树,不适用指针)

vjudge提交链接

You are to determine the value of the leaf node in a given binary tree that is the terminal node of a path of least value from the root of the binary tree to any leaf. The value of a path is the sum of values of nodes along that path.

Input
The input file will contain a description of the binary tree given as the inorder and postorder traversal sequences of that tree. Your program will read two line (until end of file) from the input file. The first line will contain the sequence of values associated with an inorder traversal of the tree and the second line will contain the sequence of values associated with a postorder traversal of the tree. All values will be different, greater than zero and less than 10000. You may assume that no binary tree will have
more than 10000 nodes or less than 1 node.

Output
For each tree description you should output the value of the leaf node of a path of least value. In the case of multiple paths of least value you should pick the one with the least value on the terminal node.

Sample Input
3 2 1 4 5 7 6
3 1 2 5 6 7 4
7 8 11 3 5 16 12 18
8 3 11 7 16 18 12 5
255
255

Sample Output
1
3
255

题意:

给出树的中序和后序,找出一条从根到叶最短路径(路径上的权值相加之和),最后输出该叶子结点的权值。如果最短路径有多条,输出叶子结点权值最小的那一个。

解题思路:

首先利用中序和后序构建二叉树,之后利用先序遍历求出最短路径,同时记录最小叶子结点的权值。

需要注意的小问题:

  1. 没有说明叶结点的个数,需要用它来搞定bool read_list(int *a),c++里面的东西,也不是很难理解
  2. 关于二叉树的构建,这里巧妙利用了lch,rch数组去模拟出二叉树的样子,从而没有使用指针。
  3. 类似的操作点这里

代码:

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<sstream>
#include<algorithm>
using namespace std;
const int maxn=10010;
const int INF=0x3f3f3f3f;
int in_order[maxn];//存中序 
int post_order[maxn];//存后序 
int lch[maxn];//存左子树 
int rch[maxn];//存右子树 
int n;//存结点个数
//把未知个数存到数组里的简单方法 
bool read_list(int *a)
{
	string line;//先看成一个字符串 
	if(!getline(cin,line))	return false;
	stringstream ss(line);
	n=0;//切记:这里不能再次定义 
	int x;
	while(ss >> x)	a[n++]=x;//将数字分割出来 
		return n>0; 
}
int build(int l1,int r1,int l2,int r2)//递归建树,l1,r1代表中序,l2,r2代表后序 
{
	if(l1>r1)	return 0;//当左大于右时停止
	int root=post_order[r2];//后序的最后一个为根
	int  p=l1;
	while(in_order[p]!=root)	p++;//找到根的位置
	int cnt=p-l1;//因为中序的根在中间,所以减去l1后恰好算出左子树的个数
	//这里cnt非常棒,一开始真的没看懂,这里考虑一下后序遍历特点:左右根
	//根已经在中序中找到,同时呢还知道根的左边有cnt个结点,当然也可知晓右子树有几个结点(这里知道一个即可) 
	//因为我们一般习惯于利用中序遍历去左右子树,其实当我们知道左右子树个数时,利用后序遍历也是可以分左右子树的 
 
	lch[root]=build(l1,p-1,l2,l2+cnt-1);//分别中序和后序的左子树 
	rch[root]=build(p+1,r1,l2+cnt,r2-1);//分别中序和后序的右子树 
	return root;
}
int best,best_sum;
void dfs(int root,int sum)//先序:根左右 
{
	sum+=root;//求权值和
	if(!lch[root]&&!rch[root])
	{
		if(sum<best_sum||(sum==best_sum&&root<best))
		{
			best=root;
			best_sum=sum;
		}
	}
	if(lch[root])
		dfs(lch[root],sum);//左
	if(rch[root])
		dfs(rch[root],sum);//右
	return; 
}
int main()
{
	while(read_list(in_order))
	{
		read_list(post_order);
		build(0,n-1,0,n-1);
		best_sum=INF;
		dfs(post_order[n-1],0);
		printf("%d\n",best);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Helinshan/article/details/114548557