《剑指offer》面试题6:重建二叉树

面试题6:重建二叉树

题目:输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

例如,前序遍历序列{1, 2, 4, 7, 3, 5, 6, 8},中序遍历序列{4, 7, 2, 1, 5, 3, 8, 6},则重建二叉树结果如下。


想清楚如何在前序遍历和中序遍历的序列中确定左右子树的子序列之后,递归实现代码如下:

/**
*	《剑指offer》 面试题6:重建二叉树
*	题目:输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。
*
*	@date: 2014-06-26
*/
#include <iostream>
#include <stdexcept>
using namespace std;

struct BTNode {
	int m_nValue;
	BTNode *m_pLeft;
	BTNode *m_pRight;
	BTNode(int v) : m_nValue(v), m_pLeft(NULL), m_pRight(NULL) {}
};

void PostOrder(BTNode *pRoot)
{
	if (pRoot)
	{
		PostOrder(pRoot->m_pLeft);
		PostOrder(pRoot->m_pRight);
		cout << pRoot->m_nValue << "\t";
	}
}

void Destroy(BTNode *pRoot)
{
	if (pRoot)
	{
		Destroy(pRoot->m_pLeft);
		Destroy(pRoot->m_pRight);
		delete pRoot;
	}
}

BTNode* ConstructCore(int *startPreorder, int *startInorder, int length)
{
	if (length == 0)
		return NULL;
	int leftLen = 0;
	while (leftLen < length && *(startInorder + leftLen) != *startPreorder)
		++leftLen;
	if (leftLen == length)
		throw invalid_argument("Invalid input.");
	BTNode *pRoot = new BTNode(*startPreorder);
	pRoot->m_pLeft = ConstructCore(startPreorder + 1, startInorder, leftLen);
	pRoot->m_pRight = ConstructCore(startPreorder + 1 + leftLen, startInorder + leftLen + 1, length - 1 - leftLen);
	
	return pRoot;
}

BTNode* Construct(int *preorder, int *inorder, int length)
{
	if (preorder == NULL || inorder == NULL || length <= 0)
		return NULL;
	return ConstructCore(preorder, inorder, length);
}

void Test()
{
	int pre[8] = {1, 2, 4, 7, 3, 5, 6, 8};
	int in[8] = {4, 7, 2, 1, 5, 3, 8, 6};
	BTNode *pRoot = Construct(pre, in, 8);
	PostOrder(pRoot);
	Destroy(pRoot);
}

int main()
{
	Test();

	return 0;
}

拓展:已知二叉树的中序遍历和后序遍历结果,重建二叉树。

/**
*	题目:输入某二叉树的中序遍历和后序遍历的结果,请重建该二叉树。
*
*	@date: 2014-06-26
*/
#include <iostream>
#include <stdexcept>
using namespace std;

struct BTNode {
	int m_nValue;
	BTNode *m_pLeft;
	BTNode *m_pRight;
	BTNode(int v) : m_nValue(v), m_pLeft(NULL), m_pRight(NULL) {}
};

void InOrder(BTNode *pRoot)
{
	if (pRoot)
	{
		InOrder(pRoot->m_pLeft);
		cout << pRoot->m_nValue << "\t";
		InOrder(pRoot->m_pRight);
	}
}

void PreOrder(BTNode *pRoot)
{
	if (pRoot)
	{
		cout << pRoot->m_nValue << "\t";
		PreOrder(pRoot->m_pLeft);
		PreOrder(pRoot->m_pRight);
	}
}

void PostOrder(BTNode *pRoot)
{
	if (pRoot)
	{
		PostOrder(pRoot->m_pLeft);
		PostOrder(pRoot->m_pRight);
		cout << pRoot->m_nValue << "\t";
	}
}

void Destroy(BTNode *pRoot)
{
	if (pRoot)
	{
		Destroy(pRoot->m_pLeft);
		Destroy(pRoot->m_pRight);
		delete pRoot;
	}
}

BTNode* ConstructCore(int *startInorder, int *startPostorder, int length)
{
	if (length == 0)
		return NULL;
	int leftLen = 0;
	while (leftLen < length && *(startInorder + leftLen) != *(startPostorder + length - 1))
		++leftLen;
	if (leftLen == length)
		throw invalid_argument("Invalid input.");
	BTNode *pRoot = new BTNode(*(startPostorder + length - 1));
	pRoot->m_pLeft = ConstructCore(startInorder, startPostorder, leftLen);
	pRoot->m_pRight = ConstructCore(startInorder + 1 + leftLen, startPostorder + leftLen, length - 1 - leftLen);
	
	return pRoot;
}

BTNode* Construct(int *inorder, int *postorder, int length)
{
	if (inorder == NULL || postorder == NULL || length <= 0)
		return NULL;
	return ConstructCore(inorder, postorder, length);
}

void Test()
{
	int in[8] = {4, 7, 2, 1, 5, 3, 8, 6};
	int post[8] = {7, 4, 2, 5, 8, 6, 3, 1};
	BTNode *pRoot = Construct(in, post, 8);
	PreOrder(pRoot);
	cout << endl;
	InOrder(pRoot);
	cout << endl;
	PostOrder(pRoot);
	Destroy(pRoot);
}

int main()
{
	Test();

	return 0;
}

已知二叉树的前序遍历结果和后序遍历结果,不能构造二叉树。


《编程之美》3.9 重建二叉树

题目:已知二叉树的前序遍历和中序遍历结果,重建该二叉树。

与《剑指offer》面试题6相同,只是输入参数变成了以null结尾的遍历结果的字符串数组。代码实现如下:

/**
*	编程之美:3.9 重建二叉树
*	已知前序遍历和中序遍历结果,重建二叉树。
*
*	@date: 2014-06-26
*/
#include <iostream>
#include <stdexcept>
using namespace std;

struct BTNode {
	char value;
	BTNode *pLeft;
	BTNode *pRight;
	BTNode(char c) : value(c), pLeft(NULL), pRight(NULL) {}
};

void RebuildTreeCore(char *Pre, char *In, int len, BTNode **pRoot)
{
	if (Pre == NULL || In == NULL || len < 1)
	{
		pRoot = NULL;
		return;
	}
	int leftLen = 0;
	while (leftLen < len && *(In + leftLen) != *Pre)
		++leftLen;
	if (leftLen == len)
		 throw invalid_argument("Invalid input.");
	*pRoot = new BTNode(*Pre);
	RebuildTreeCore(Pre + 1, In, leftLen, &((*pRoot)->pLeft));
	RebuildTreeCore(Pre + 1 + leftLen, In + leftLen + 1, len - leftLen - 1, &((*pRoot)->pRight));
}

BTNode* RebuildTree(char *Pre, char *In)
{
	if (Pre == NULL || In == NULL)
		return NULL;
	int len1 = 0, len2 = 0;
	char *pCh = Pre;
	while (*pCh != '\0')
	{
		++pCh;
		++len1;
	}
	pCh = In;
	while (*pCh != '\0')
	{
		++pCh;
		++len2;
	}
	if (len1 != len2 || len1 <= 0)
		return NULL;
	BTNode *pRoot;
	RebuildTreeCore(Pre, In, len1, &pRoot);
	
	return pRoot;
}

void PostOrder(BTNode *pRoot)
{
	if (pRoot)
	{
		PostOrder(pRoot->pLeft);
		PostOrder(pRoot->pRight);
		cout << pRoot->value << "\t";
	}
}

void Destroy(BTNode *pRoot)
{
	if (pRoot)
	{
		Destroy(pRoot->pLeft);
		Destroy(pRoot->pRight);
		delete pRoot;
	}
}

void Test()
{
	char Pre[] = "abdcef";
	char In[] = "dbaecf";
	BTNode *pRoot = RebuildTree(Pre, In);
	PostOrder(pRoot);
	Destroy(pRoot);
}

int main()
{
	Test();

	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值