剑指Offer面试题6重建二叉树(根据前序中序输出后序)

面试题6:重建二叉树。

输入二叉树的前序遍历和中序遍历结果,重建二叉树。假设输入的前序和中序结果都不含重复的数,例如:前序12473568,中序47215386,输出后序遍历结果。
思路:所谓前中后序即根节点的访问顺序。前序的第一个数肯定是根节点,而根节点在中序里的中间位置,其左为左子树,右边是右子树。
假设中序的根节点左边有3个数,可知根节点的左子树有3个节点,此时这三个数的顺序即是左子树的中序。那么前序的第一个数的后边三个数肯定也是左子树,并且是该左子树的前序。

那么左右子树的前序和中序都有了,就可以递归了。下面提供了Java和C语言的实现:

Java实现:

class BinaryTreeNode{
	int value;
	BinaryTreeNode leftNode,rightNode;
}
public class Construct {
	static BinaryTreeNode rebuild(int[] preorder,int[] inorder){
		BinaryTreeNode root = rebuild(preorder,0,preorder.length-1,inorder,0,inorder.length-1);
		return root;
	}
	//参数包含子遍历,以及遍历开始和结束的位置
	static BinaryTreeNode rebuild(int[] preorder,int startPre,int endPre,int[] inorder,int startIn,int endIn){
		if( startPre > endPre || startIn > endIn || preorder.length != inorder.length){
			return null;
		}
		boolean haveRoot = false;
		//前序第一个数为根节点
		BinaryTreeNode root = new BinaryTreeNode();
		for(int i=startIn;i<=endIn;i++){
			//找根节点
			if(inorder[i] == preorder[startPre]){
				haveRoot = true;
				root.value = preorder[startPre];
				root.leftNode = rebuild(preorder, startPre+1, startPre+1+(i-startIn), inorder, startIn, i-1);
				root.rightNode = rebuild(preorder, i-startIn+startPre+1, endPre, inorder, i+1, endIn);
				//用数组索引比较复杂,另一种用复制数组的方法好理解。
				//root.leftNode = rebuild(Arrays.copyOfRange(preorder, 1, i+1), Arrays.copyOfRange(inorder, 0, i));
				//root.rightNode = rebuild(Arrays.copyOfRange(preorder, i+1, preorder.length), Arrays.copyOfRange(inorder, i+1,inorder.length));
			}
		}
		if(!haveRoot){
			System.out.println("没有找到根节点");
			return null;
		}
		return root;
	}
	//后序遍历树
	static void postorder(BinaryTreeNode root){
		if(root == null){
			System.out.println("根节点为空");
		}
		if(root.leftNode != null){
			postorder(root.leftNode);
		}
		if(root.rightNode != null){
			postorder(root.rightNode);
		}
		System.out.println(root.value);
	}
	public static void main(String[] args) {
		int[] preorder = {1,2,4,7,3,5,6,8};
		int[] inorder = {4,7,2,1,5,3,8,6};
		postorder(rebuild(preorder, inorder));
	}
}

C语言实现:

#include<stdio.h>
#include<stdlib.h>
typedef struct TreeNode{
	int value;
	TreeNode* left;
	TreeNode* right;
}BiTree,*pTree;

TreeNode* constructCore(int* startpre,int* endpre,int* startin,int* endin){//参数为前序开始结束的位置,中序开始结束的位置
	//前序第一个数是根节点的值
	pTree root = (pTree)malloc(sizeof(BiTree));
	root->value = startpre[0];
	root->left = root->right = NULL;
	if(startpre == endpre){
		if(startin == endin && *startpre == *startin) return root;//重建完成
		else printf("错误的输入");
	}
	//在中序中找根节点的值
	int* rootInorder = startin;
	while(rootInorder <= endin && *rootInorder != root->value) ++rootInorder;
	if(rootInorder == endin && *rootInorder != root->value) printf("还是错误的输入");
	int leftLen = rootInorder - startin;
	int* leftEndpre = startpre + leftLen;
	if(leftLen >0){
		//构建左子树
		root->left = constructCore(startpre +1,leftEndpre,startin,rootInorder -1);
	}
	if(leftLen < endpre-startpre){
		//构建右子树,上述条件是左子树个数小于所有子树个数,所以必存在右子树
		root->right = constructCore(leftEndpre +1,endpre,rootInorder +1,endin);
	}
	return root;
}

TreeNode* construct(int* preorder,int* inorder,int length){//数组作为参数时,传入的是地址。
	if(preorder ==NULL || inorder == NULL || length<=0) return NULL;
	return constructCore(preorder,preorder + length -1,inorder,inorder + length -1);
}
//后序输出
void postorder(pTree root){
	if(root == NULL) printf("后序为空");
	if(root->left != NULL) postorder(root->left);
	if(root->right != NULL) postorder(root->right);
	printf("%d",root->value);
	printf("\n");
}
int main(){
	pTree rootNode;
	int a[] = {1,2,4,7,3,5,6,8};//前序
	int b[] = {4,7,2,1,5,3,8,6};//中序
	rootNode = construct(a,b,8);
	postorder(rootNode);
	return 0;
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值