您的位置:首页 > Web前端

剑指offer 6- 重建二叉树

2015-05-19 20:32 316 查看
对于一颗二叉树,可以根据先序遍历(后序遍历)和中序遍历重新还原出二叉树。

根据先序遍历和中序遍历还原二叉树的主要思想:

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

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

3、分别对左子树和右子树重复上述的过程,直至所有的子树的起止位置相等时,说明已经到达叶子节点,遍历完毕。

#include <iostream>
#include<exception>
using namespace std;

struct BinaryTreeNode
{
int m_nValue;
BinaryTreeNode* m_pLeft;
BinaryTreeNode* m_pRight;
};

BinaryTreeNode* Construct( int* startPreorder, int* endPreorder, int* startInorder, int* endInorder )
{
if(startPreorder == NULL || endPreorder==NULL || startInorder==NULL || endInorder==NULL)
return NULL;

int rootValue = startPreorder[0]; //前序遍历 根节点
BinaryTreeNode* root = new BinaryTreeNode[sizeof(BinaryTreeNode)];
root->m_nValue = rootValue;
root->m_pLeft = root->m_pRight = NULL;

if(startPreorder == endPreorder )
{
if( startInorder == endInorder&& *startPreorder==* startInorder ) //只有根节点
return root;
else
throw std::exception("Invalid input");
}

int* rootInorder = startInorder;
while( rootInorder<=endInorder && *rootInorder!=rootValue ) // 找到中序遍历根节点位置
++rootInorder;
int leftLength = rootInorder - startInorder; //从而得到左子树的位数
int* 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;

}

void printTreeNode( BinaryTreeNode* root ) //前序遍历打印
{
if(root !=NULL)
{
cout<<root->m_nValue;
printTreeNode(root->m_pLeft);
printTreeNode(root->m_pRight);
}
}

void DestroyTree( BinaryTreeNode* pRoot )
{
if(pRoot != NULL)
{
BinaryTreeNode* pLeft = pRoot->m_pLeft;
BinaryTreeNode* pRight = pRoot->m_pRight;

delete pRoot;
pRoot = NULL;

DestroyTree(pLeft);
DestroyTree(pRight);
}
}
// ====================测试代码====================
void Test(char* testName, int* preorder, int* inorder, int length)
{
if(testName != NULL)
printf("%s begins:\n", testName);

printf("The preorder sequence is: ");
for(int i = 0; i < length; ++ i)
printf("%d ", preorder[i]);
printf("\n");

printf("The inorder sequence is: ");
for(int i = 0; i < length; ++ i)
printf("%d ", inorder[i]);
printf("\n");

try
{
BinaryTreeNode* root = Construct(preorder,preorder+length-1, inorder, inorder+length-1);
printTreeNode(root);

DestroyTree(root);
}
catch(std::exception& exception)
{
printf("Invalid Input.\n");
}
printf("\n");
}

// 普通二叉树
// 1
// / \
// 2 3
// / / \
// 4 5 6
// \ /
// 7 8
void Test1()
{
const int length = 8;
int preorder[length] = {1, 2, 4, 7, 3, 5, 6, 8};
int inorder[length] = {4, 7, 2, 1, 5, 3, 8, 6};

Test("Test1", preorder, inorder, length);
}

// 所有结点都没有右子结点
// 1
// /
// 2
// /
// 3
// /
// 4
// /
// 5
void Test2()
{
const int length = 5;
int preorder[length] = {1, 2, 3, 4, 5};
int inorder[length] = {5, 4, 3, 2, 1};

Test("Test2", preorder, inorder, length);
}

// 所有结点都没有左子结点
// 1
// \
// 2
// \
// 3
// \
// 4
// \
// 5
void Test3()
{
const int length = 5;
int preorder[length] = {1, 2, 3, 4, 5};
int inorder[length] = {1, 2, 3, 4, 5};

Test("Test3", preorder, inorder, length);
}

// 树中只有一个结点
void Test4()
{
const int length = 1;
int preorder[length] = {1};
int inorder[length] = {1};

Test("Test4", preorder, inorder, length);
}

// 完全二叉树
// 1
// / \
// 2 3
// / \ / \
// 4 5 6 7
void Test5()
{
const int length = 7;
int preorder[length] = {1, 2, 4, 5, 3, 6, 7};
int inorder[length] = {4, 2, 5, 1, 6, 3, 7};

Test("Test5", preorder, inorder, length);
}

// 输入空指针
void Test6()
{
Test("Test6", NULL, NULL, 0);
}

// 输入的两个序列不匹配
void Test7()
{
const int length = 7;
int preorder[length] = {1, 2, 4, 5, 3, 6, 7};
int inorder[length] = {4, 2, 8, 1, 6, 3, 7};

Test("Test7: for unmatched input", preorder, inorder, length);
}

int main(int argc, char* argv[])
{
Test1();
Test2();
Test3();
Test4();
Test5();
Test6();
Test7();

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: