剑指offer-6

题目描述:

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{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”。

样例输入:
81 2 4 7 3 5 6 84 7 2 1 5 3 8 681 2 4 7 3 5 6 84 1 2 7 5 3 8 6
样例输出:
7 4 2 5 8 6 3 1 No

重建二叉树

第一:对于一棵树可以根据其先序遍历(根左右)和遍历(左根右) 或是遍历(左右根)和遍历(左根右)来重建其二叉树。

那么能不能由先序遍历和后续遍历重建二叉树呢?显然是不可以的!因为先序遍历和后续遍历都只能确定根节点,而无法确定左右子树的边界。所以无法递归下去。

而对于第一行中提及的另外两种情况都是可以的,因为根据先序或是后续遍历可以唯一确定树的根节点,再根据中续遍历可以确定出左右子树。递归,直到叶子节点。则可重建出二叉树。

第二:算法的核心:就是递归建树。

第三:算法的思想:

1、先序遍历的第一个元素或后序遍历的最后一个元素必定是根节点,可以由此获取二叉树的根节点。

2、根据根节点,在中序遍历序列中查找该节点,由中序遍历的性质可知,中序遍历中该根节点左边的序列必定在根节点的左子树中,而根节点右边的序列必定在右子树中。由此可以知道先序遍历中左子树以及右子树的起止位置。

3、分别对左子树和右子树重复上述的过程,直至所有的子树的起止位置相等时(注意这一句话非常关键,这是递归是否结束的条件,代码实现时的关键),说明已经到达叶子节点,遍历完毕。

实现代码如下:

#include<stdio.h>
#include<stdlib.h>

typedef struct node
{
	struct node *leftnode;
	struct node *rightnode;
	int value;
}BinaryTreeNode;

int flag;
//输出先序遍历
void preorderTraverse(BinaryTreeNode *p)
{
	//I think there is not difference having it or not.
	//if the initial value of 'p' is NULL 'if' sentence will be useful!!!	
	if(NULL==p)
	{
		return 0;
	}
	
	printf("%d ",p->value);
	
	if(NULL!=p->leftnode)
	{
		preorderTraverse(p->leftnode);
	}
	if(NULL!=p->rightnode)
	{
		preorderTraverse(p->rightnode);
	}
}

//输出中序遍历

int inorderTraverse(BinaryTreeNode *p)
{
	
	if(NULL==p)
	{
		return 0;
	}
	
	if(NULL!=p->leftnode)
	{
		inorderTraverse(p->leftnode);
	}
	printf("%d ",p->value);
	if(NULL!=p->rightnode)
	{
		inorderTraverse(p->rightnode);
	}
}

//输出后序遍历
int postorderTraverse(BinaryTreeNode *p)
{
	
	if(NULL==p)
	{
		return 0;
	}
	
	if(NULL!=p)
	{
		postorderTraverse(p->leftnode);
	}
	if(NULL!=p)
	{
		postorderTraverse(p->rightnode);
	}
	printf("%d ",p->value);
}
BinaryTreeNode* recusiveBuildBinaryTree(int *pPreStart,int *pPreEnd,int *pInStart,int *pInEnd,int n)
{
	BinaryTreeNode *pRoot=NULL;
	int rootvalue=0;
	int i=0;

	int *leftPreStart,*leftPreEnd,*rightPreStart,*rightPreEnd;
	int *leftInStart,*leftInEnd,*rightInStart,*rightInEnd;

	rootvalue=pPreStart[0];
	pRoot=(BinaryTreeNode*)malloc(sizeof(BinaryTreeNode));
	pRoot->value=rootvalue;
	pRoot->leftnode=pRoot->rightnode=NULL;

	while(rootvalue!=pInStart[i])
	{
		i++;
		if(i>=n)
		{
			flag=0;
			return NULL;
		}
	}

	leftPreStart=pPreStart+1;
	leftPreEnd=pPreStart+i;
	leftInStart=pInStart;
	leftInEnd=pInStart+i-1;

	rightPreStart=pPreStart+i+1;
	rightPreEnd=pPreEnd;
	rightInStart=pInStart+i+1;
	rightInEnd=pInEnd;
<span style="white-space:pre">	</span>///此处之上为创建本节点,并为下次递归做好准备。
	if(leftInStart<=leftInEnd)///临界条件真是个大难题。
	{
		pRoot->leftnode=recusiveBuildBinaryTree(leftPreStart,leftPreEnd,leftInStart,leftInEnd,i);
		
	}
	if(rightInStart<=rightInEnd)
	{
		pRoot->rightnode=recusiveBuildBinaryTree(rightPreStart,rightPreEnd,rightInStart,rightInEnd,n-i-1);
	}
	return pRoot;
}
BinaryTreeNode* buildBinaryTree(int *pPre,int *pIn,int n)
{
	BinaryTreeNode *root=NULL;
	if(pPre==NULL && pIn==NULL)
	{
		printf("malloc failed");
	}
	root=recusiveBuildBinaryTree(pPre,pPre+n-1,pIn,pIn+n-1,n);
	return root;
}

int main()
{
	int n=0;
	int i=0,j=0;
	int *pPreorder=NULL;
	int *pInorder=NULL;
	BinaryTreeNode *root=NULL;
	while(scanf("%d",&n))
	{
		flag=1;
		pPreorder=malloc(sizeof(int)*n);
		pInorder=malloc(sizeof(int)*n);
		for(i=0;i<n;i++)
		{
			scanf("%d",&pPreorder[i]);
		}
		for(i=0;i<n;i++)
		{
			scanf("%d",&pInorder[i]);
		}
		root=buildBinaryTree(pPreorder,pInorder,n);
	
		if(flag==1)
		{
			postorderTraverse(root);
			printf("\n");
		}
		else
		{
			printf("No\n");
		}

	}
	return 0;
}

这段代码提交到九度online judge上之后提示:Output Limit Exceeded : 输出超过限制,你的输出比正确答案长了两倍。

目前还未解决这个问题!


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值