輸入二叉樹的前序遍歷和中序遍歷,重建出該二叉樹

題目:輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設前序遍歷與中序遍歷的結果都不含重複的數字。

eg:前序遍歷:{1,2,4,7,3,5,6,8};
        中序遍歷:{4,7,2,1,5,3,8,6};

二叉樹結點定義如下:
struct BinaryTreeNode
{
int _value;
BinaryTreeNode* _left;
BinaryTreeNode* _right;
}

c++實現函數說明:
本題的函數主要是有參構造函數:BinaryTree(int* pre, int* inOrder, int len);
有參構造函數調用函數:BinaryTreeNode* _CreateBinaryTree(BinaryTreeNode*& root,int*& pre, int*& inOrder, int len);
此函數又調用了主要函數:BinaryTreeNode* _RealCreateTree(BinaryTreeNode*& root,int* startPre, int* endPre, int* startIn, int* endIn);

函數void _DestoryBinaryTree(BinaryTreeNode*& root);:遞歸銷燬一棵樹;

分析如下:
1.先根據先序遍歷創建出根結點:root;
2.再通過中序遍歷找出根結點,用根結點的下標計算出左子樹的個數;
3.再通過左子樹的個數計算出在先序遍歷中左子樹結尾的位置;
4.通過以上計算,我們已經將二叉樹分爲左子樹和右子樹,然後大問題化作小問題;
5.遍歷左子樹;
6.遍歷右子樹;


依據上面的思路構建出的二叉樹如上圖:

代碼如下:

#include<iostream>
using namespace std;
struct BinaryTreeNode
{
	int _value;
	BinaryTreeNode* _left;
	BinaryTreeNode* _right;

	BinaryTreeNode(int value = 0)
		:_value(value),_left(NULL), _right(NULL)
	{}
};
class BinaryTree
{
public:
	BinaryTree()
		:root(NULL)
	{}

	BinaryTree(int* pre, int* inOrder, int len)
	{
		_CreateBinaryTree(root, pre, inOrder, len);
	}

	~BinaryTree()
	{
		_DestoryBinaryTree(root);
	}

private:
	void _DestoryBinaryTree(BinaryTreeNode*& root)
	{
		if (root)
		{
			BinaryTreeNode* tmp = root;
			if (tmp->_left)
			{
				_DestoryBinaryTree(tmp->_left);
			}
			if (tmp->_right)
			{
				_DestoryBinaryTree(tmp->_right);
			}
			delete[] tmp;
			tmp = NULL;
		}
	}

	BinaryTreeNode* _CreateBinaryTree(BinaryTreeNode*& root,int*& pre, int*& inOrder, int len)
	{
		if (pre == NULL || inOrder == NULL || len <= 0)
		{
			return NULL;
		}
		return _RealCreateTree(root, pre, pre + len - 1, inOrder, inOrder + len - 1);
	}

	BinaryTreeNode* _RealCreateTree(BinaryTreeNode*& root,int* startPre, int* endPre, int* startIn, int* endIn)
	{
		int rootValue = startPre[0];
		root = new BinaryTreeNode(rootValue);
		
		//1.有一個結點
		if (startPre == endPre)
		{
			if (startIn == endIn && *startPre == *startIn)
			{
				return root;
			}
			else
			{
				cout << "preOrder and InOder is not matching" << endl;
				return NULL;
			}
		}
		
		//2.有多個結點
		int* rootIn = startIn;
		while (rootIn < endIn && *rootIn != root->_value)
		{
			++rootIn;
		}
		if (rootIn == endIn && *rootIn != root->_value)
		{
			cout << "preOrder and InOder is not matching" << endl;
			return NULL;
		}

		//1.通過中序遍歷計算左子樹的節點個數leftLen
		//2.通過計算出的左子樹個數,再計算先序遍歷中的左子樹中的最後一個節點位置preLeftOfend
		int leftLen = rootIn - startIn;
		int* preLeftOfend = startPre + leftLen;

		//構建左子樹
		if (leftLen > 0)
		{
			_RealCreateTree(root->_left, startPre + 1, preLeftOfend, startIn, rootIn - 1);
		}

		//構建右子樹
		if (leftLen < endPre - startPre)
		{
			_RealCreateTree(root->_right, preLeftOfend + 1, endPre, rootIn + 1, endIn);

		}
		return root;
	}

private:
	BinaryTreeNode* root;
};

void Test()
{
	int pre[] = { 1, 2, 4, 7, 3, 5, 6, 8 };
	int in[] = { 4, 7, 2, 1, 5, 3, 8, 6 };
	int len = sizeof(pre) / sizeof(pre[0]);
	BinaryTree bt(pre, in, len);
}

void Test2()
{
	int pre[] = { 1, 2, 4, 8, 9, 5, 3, 6, 7 };
	int in[] = { 8, 4, 9, 2, 5, 1, 6, 3, 7 };
	int len = sizeof(pre) / sizeof(pre[0]);
	BinaryTree bt(pre, in, len);
}

void Test3()
{
	int pre[] = { 1, 2, 3, 4, 5, 6 };
	int in[] = { 6, 5, 4, 3, 2, 1 };
	int len = sizeof(pre) / sizeof(pre[0]);
	BinaryTree bt(pre, in, len);
}

void Test4()
{
	int pre[] = { 1, 2, 3, 4, 5, 6 };
	int in[] = { 1, 2, 3, 4, 5, 6 };
	int len = sizeof(pre) / sizeof(pre[0]);
	BinaryTree bt(pre, in, len);
}

void Test5()
{
	int pre[] = { 10 };
	int in[] = { 10 };
	int len = sizeof(pre) / sizeof(pre[0]);
	BinaryTree bt(pre, in, len);
}

void Test6()
{
	int pre[] = { 1,2,3,4,5};
	int in[] = {4,5,7,3,1};
	int len = sizeof(pre) / sizeof(pre[0]);
	BinaryTree bt(pre, in, len);
}

int main()
{
	//1.普通二叉樹:Test():不完全二叉樹;
	//				Test2():完全二叉樹;			
	//2.特殊二叉樹:Test3():所有結點沒有右結點;
	//				Test4():所有結點沒有左節點;
	//				Test5():只有一個結點;
	//3.特殊測試:	Test6():輸入的前序與中序不匹配;
	Test();
	Test2();
	Test3();
	Test4();
	Test5();
	Test6();
	return 0;
}


除Test6()外,所有測試都可以通過調試去看構造出的二叉樹結構;
Test6()測試不匹配的結果如下圖所示:


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章