-
题目描述:online judge
-
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并输出它的后序遍历序列。
-
输入:
-
输入可能包含多个测试样例,对于每个测试案例,
输入的第一行为一个整数n(1<=n<=1000):代表二叉树的节点个数。
输入的第二行包括n个整数(其中每个元素a的范围为(1<=a<=1000)):代表二叉树的前序遍历序列。
输入的第三行包括n个整数(其中每个元素a的范围为(1<=a<=1000)):代表二叉树的中序遍历序列。
-
输出:
-
对应每个测试案例,输出一行:
如果题目中所给的前序和中序遍历序列能构成一棵二叉树,则输出n个整数,代表二叉树的后序遍历序列,每个元素后面都有空格。
如果题目中所给的前序和中序遍历序列不能构成一棵二叉树,则输出”No”。
-
样例输入:
-
8 1 2 4 7 3 5 6 8 4 7 2 1 5 3 8 6 8 1 2 4 7 3 5 6 8 4 1 2 7 5 3 8 6
-
样例输出:
-
7 4 2 5 8 6 3 1 No
-
问题分析:
性质:二叉树的前序遍历中第一个数字总是根节点的值,中序遍历中根节点把遍历序列分为左右两颗子树。利用者两个特性我们可以重建二叉树。具体如何重建,笔者建议读者自己在草稿纸上举几个例子。弄清楚重建的过程,然后在开始编码。
java代码:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
public class Problem_06 {
private int[] preorder;
private int[] inorder;
private BinaryTreeNode root;
private boolean isTree = true;
private StringBuilder sb;
public Problem_06(int[] preorder, int[] inorder){
this.preorder = preorder;
this.inorder = inorder;
root = construct(preorder, inorder);
sb = new StringBuilder();
}
private BinaryTreeNode construct(int[] preorder, int[] inorder) {
if(preorder.length == 0 || inorder.length == 0){
isTree = false;
return null;
}
return constructCore(0, preorder.length - 1, 0, inorder.length -1);
}
private BinaryTreeNode constructCore(int startPreorder, int endPreorder,
int startInorder, int endInorder) {
int rootValue = preorder[startPreorder];
BinaryTreeNode root = new BinaryTreeNode();
root.value = rootValue;
if(startPreorder == endPreorder){
if(startInorder == endInorder
&& preorder[startPreorder] == inorder[startInorder]){
return root;
}else{
isTree = false;
return null;
}
}
//从中序遍历中找到根节点
int rootInorder = startInorder;
while(rootInorder <= endInorder && inorder[rootInorder] != rootValue){
++rootInorder;
}
if(rootInorder > endInorder ||
(rootInorder == endInorder && inorder[rootInorder] != rootValue)){
isTree = false;
return null;
}
int leftLength = rootInorder - startInorder;
int leftPreorder = startPreorder + leftLength;
if(leftLength > 0 && isTree){
root.left = constructCore(startPreorder + 1, leftPreorder, startInorder, rootInorder -1 );
}
if(leftLength < endPreorder - startPreorder && isTree){
root.right = constructCore(leftPreorder + 1, endPreorder, rootInorder + 1, endInorder);
}
return root;
}
private void postTree(BinaryTreeNode root) {
if (root.left != null)
postTree(root.left);
if (root.right != null)
postTree(root.right);
sb.append(root.value+" ");
}
public void showTree() {
if (isTree) {
postTree(root);
System.out.println(sb.toString());
} else {
System.out.println("No");
}
}
class BinaryTreeNode{
int value;
BinaryTreeNode left;
BinaryTreeNode right;
}
public static void main(String[] args) throws IOException {
BufferedReader buf = new BufferedReader( new InputStreamReader(System.in));
StreamTokenizer str = new StreamTokenizer(buf);
while(str.nextToken() != StreamTokenizer.TT_EOF){//元素录入
int length = (int)str.nval;
int preorder[] = new int[length];
int inorder[] = new int[length];
for(int i = 0; i < preorder.length; i ++){
str.nextToken();
preorder[i] = (int)str.nval;
}
for(int i = 0; i < inorder.length; i ++){
str.nextToken();
inorder[i] = (int)str.nval;
}
new Problem_06(preorder,inorder).showTree();
}
}
}
C++代码:
#include<iostream>
#include<stdio.h>
using namespace std;
#define N 10000
struct BinaryTreeNode{
int m_nValue;
BinaryTreeNode *m_pLeft;
BinaryTreeNode *m_pRight;
};
bool bo;
BinaryTreeNode *ConstructCore(int *startPreorder, int *endPreorder, int *startInorder, int *endInorder)
{
int rootValue = startPreorder[0];
BinaryTreeNode *root = new BinaryTreeNode();
root->m_nValue = rootValue;
root->m_pLeft = root->m_pRight = NULL;
if(startPreorder == endPreorder)
{
if(startInorder == endInorder && *startPreorder == *startInorder)
return root;
else
{
bo = false;
return NULL;
}
}
int *rootInorder = startInorder;
while(rootInorder <= endInorder && *rootInorder != rootValue)
{
rootInorder++;
}
if(rootInorder == NULL || *rootInorder != rootValue)
{
bo = false;
return NULL;
}
int leftLength = rootInorder - startInorder;
int *leftPreorderEnd = startPreorder + leftLength;
if(leftLength > 0)
{
root->m_pLeft = ConstructCore(startPreorder + 1, leftPreorderEnd, startInorder, rootInorder - 1);
}
if(endPreorder - startPreorder > leftLength)
{
root->m_pRight = ConstructCore(leftPreorderEnd + 1, endPreorder, rootInorder + 1, endInorder);
}
return root;
}
BinaryTreeNode *Construct(int *preorder, int *inorder, int length)
{
if(preorder == NULL || inorder == NULL || length <= 0)
{
bo = false;
return NULL;
}
return ConstructCore(preorder, preorder + length -1, inorder, inorder + length -1);
}
void tailPrint(BinaryTreeNode *root)
{
if(root->m_pLeft != NULL)
tailPrint(root->m_pLeft);
if(root->m_pRight != NULL)
tailPrint(root->m_pRight);
printf("%d ", root->m_nValue);
}
int main()
{
int n;
while(scanf("%d", &n) != EOF)
{
bo = true;
if(n <= 0)
{
printf("No\n");
return 0;
}
int a[N], b[N];
for(int i = 0; i < n; i++)
{
scanf("%d", &a[i]);
}
for(int j = 0; j < n; j++)
{
scanf("%d", &b[j]);
}
BinaryTreeNode *c = Construct(a, b, n);
if(bo == true && c != NULL)
{
tailPrint(c);
printf("\n");
}
else printf("No\n");
}
return 0;
}
C代码:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
typedef struct Node
{
int i;
struct Node* left;
struct Node* right;
}Node;
int isNotTree=FALSE;
Node* RebuildTree(int* preOrder,int* inOrder,int length)
{
int i=0;
if(isNotTree)
return NULL;
Node* result=(Node*)malloc(sizeof(Node));
result->left=NULL;
result->right=NULL;
if(length==0)
return NULL;
if(length==1)
{
if(*preOrder!=*inOrder)
{
isNotTree=TRUE;
return NULL;
}
result->i=*preOrder;
return result;
}
for(;*preOrder!=inOrder[i];++i);
result->i=*preOrder;
result->left=RebuildTree(preOrder+1,inOrder,i);
result->right=RebuildTree(preOrder+i+1,inOrder+i+1,length-i-1);
return result;
}
void printTree(Node* root)
{
if(root!=NULL)
{
printTree(root->left);
printTree(root->right);
printf("%d ",root->i);
}
}
int main()
{
int length;
int *preOrder,*inOrder;
int i=0;
struct Node* root=NULL;
while(scanf("%d",&length)!=EOF)
{
preOrder=(int*)malloc(length*sizeof(int));
inOrder=(int*)malloc(length*sizeof(int));
for(i=0;i<length;++i)
scanf("%d",&preOrder[i]);
for(i=0;i<length;++i)
scanf("%d",&inOrder[i]);
root=RebuildTree(preOrder,inOrder,length);
if(isNotTree==TRUE)
{
printf("No");
isNotTree=FALSE;
}
else
printTree(root);
printf("\n");
free(preOrder);
free(inOrder);
}
return 0;
}
测试用例:
普通二叉树(完全二叉树,不完全二叉树)
特殊二叉树(所有结点都没有左结点或右结点的树,只有一个结点的二叉树)
特殊输入测试(二叉树结点为null,输入前序和中序不匹配)
体会:
本人最先开始学的是C语言,对于指针在java中的一些类似功能不是特别熟悉,java
生成的对象不要人为管理,而C和C++需要人为销毁。所以java对于实现树和图等结构比C和C++更加容易。