面试经典(18)--重建二叉树

题目描述:给定二叉树的前序序列和中序序列--假设没有重复的字符,写一个算法重建这课二叉树。

要求:struct Node{

Node *m_pLeft;

Node *m_pRight;

char  m_nValue;

};

举例:

前序:a b d c e f

中序:d b a e c f

重构的二叉树:

分析:

前序遍历:先访问当前节点,然后前序访问左子树,右子树。

中序遍历:先中序遍历左子树,接着访问当前节点,然后以中序遍历右子树。

根据前序遍历和中序遍历的特点,可以发现如下规律:

前序遍历的每一个节点,都是当前子树的根节点。同时,以对应的节点为边界,就会把中序遍历的序列分隔为左子树和右子树。

前序:a b d c e f,a是根节点

中序:d b a e c f,a是根节点,将中序序列分成两个子树

这样,如果能够找到前序遍历中对应的左右子树,就可以把作为当前的根节点,然后依次递归下去,这样就能够依次恢复左右子树。

代码如下:

struct Node
{
	char m_nValue;
	Node *m_pLeft;
	Node *m_pRight;
};

Node *construct(char *startPreOrder,char *endPreOrder,char *startInOrder,char *endInOrder)
{
	//首先取得根节点,然后建立根节点
	char rootValue=*startPreOrder;
	Node *root=new Node;
	root->m_nValue=rootValue;
	root->m_pLeft=root->m_pRight=NULL;

	//退出条件:当子树仅仅有一个节点。要检测输入是否有效
	if(startPreOrder==endPreOrder)
	{
		//感觉statInOrder==endInOrder这个判断条件可以不要
		if(*startPreOrder==*startInOrder)
			return root;
		else
			throw exception("Invalid input");
	}
	//找到根节点之后,需要从中序序列中查找根节点,有可能找不到,计算左子树长度
	char *rootInOrder=startInOrder;
	while(rootInOrder<endInOrder && *rootInOrder!=rootValue)
		++rootInOrder;
	if(rootInOrder==endInOrder && *rootInOrder!=rootValue)
		throw exception("Invalid input");

	int leftLength=rootInOrder-startInOrder;
	char *leftPreOrderEnd=startPreOrder+leftLength;

	//构建左子树和右子树
	if(leftLength>0)
		root->m_pLeft=construct(startPreOrder+1,leftPreOrderEnd,startInOrder,rootInOrder-1);
	if(leftLength<endPreOrder-startPreOrder)
		root->m_pRight=construct(leftPreOrderEnd+1,endPreOrder,rootInOrder+1,endInOrder);

	return root;
}

Node *construct(char *preOrder,char *inOrder,int length)
{
	if(preOrder==NULL || inOrder==NULL || length<0)
		return NULL;
	return construct(preOrder,preOrder+length-1,inOrder,inOrder+length-1);
}

调用代码:

int main()
{
	char pre[]="abc";
	char in[]="cba";
	Node *root=NULL;
	try{
		root=construct(pre,in,sizeof(pre));
	}catch(exception e){
		cout<<e.what()<<endl;
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值