面试题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;
}