重新構建樹
題目:
輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹並返回。
思路:
首先要知道樹的前序、中序和後序遍歷,前中後都是對於根結點來說的。
前序遍歷:先訪問根結點,再訪問左子樹,最後訪問右子樹
中序遍歷:先訪問左子樹,再訪問根結點,最後訪問右子樹
**
後序遍歷:先訪問左子樹,再訪問右子樹,最後訪問根結點**
所以我們根據前序遍歷的結果,知道根結點爲1,然後在中序遍歷的結果中找到1,1左邊的元素屬於左子樹,1右邊的元素屬於右子樹。再根據左右子樹遞歸地構建。當子樹中僅有一個元素時返回。
代碼如下(爲驗證結果,打印重建樹的後序遍歷結果)
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x):val(x),left(NULL),right(NULL) {}
};
TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
if(pre.size()==0) return NULL;
if(pre.size()==1) return new TreeNode(pre[0]);
TreeNode *root = new TreeNode(pre[0]); //根結點
auto root_it = find(vin.begin(),vin.end(),pre[0]);
int left_num = root_it-vin.begin(); //左子樹結點數
int right_num = vin.end()-root_it-1; //右子樹結點數
vector<int> left_pre(pre.begin()+1,pre.begin()+left_num+1); //左子樹前序遍歷結果
vector<int> left_vin(vin.begin(),vin.begin()+left_num); //左子樹中序遍歷結果
vector<int> right_pre(pre.begin()+left_num+1,pre.end()); //右子樹前序遍歷結果
vector<int> right_vin(vin.begin()+left_num+1,vin.end()); //右子樹中序遍歷結果
root->left = reConstructBinaryTree(left_pre, left_vin); //遞歸構建左子樹
root->right = reConstructBinaryTree(right_pre, right_vin); //遞歸構建右子樹
return root;
}
void postTraverse(TreeNode *root) { //後序遍歷
if(root->left!=NULL) postTraverse(root->left);
if(root->right!=NULL) postTraverse(root->right);
cout<<root->val<<endl;
}
int main()
{
vector<int> pre = {1,2,4,5,3,6};
vector<int> vin = {4,2,5,1,6,3};
TreeNode *root = reConstructBinaryTree(pre, vin);
postTraverse(root);
return 0;
}