天天看点

面试题6:重建二叉树

题目描述:online judge
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并输出它的后序遍历序列。
面试题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++更加容易。

继续阅读