一、题目
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2, 4, 7, 3, 5, 6, 8}和中序遍历序列{4, 7, 2, 1, 5, 3, 8, 6},则重建出如所示的二叉树并输出它的头结点。
1
/ \
2 3
/ / \
4 5 6
\ /
7 8
图1. 根据前序遍历前序遍历序列{1,2, 4, 7, 3, 5, 6, 8}和中序遍历序列{4, 7, 2, 1, 5, 3, 8, 6}重建的二叉树。
二、解法
分析:前序遍历的第一个数字1就是根节点的值,扫描中序遍历序列,就能确定根节点的值的位置,根据中序遍历的特点,在根节点的值1前面的三个数字都是左子树节点的值,位于1后面的数字都是右子树节点的值。
由于在中序遍历中,有3个数字是左子树节点的值,因此左子树有3个节点,同样在前序遍历序列中,根节点后面的3个数字就是3个左子树节点的值,在后面的所有数字都是右子树节点的值,这样我们就在前序遍历和中序遍历两个序列中分别找到了左、右子树对应的子序列。
既然我们已经分别找到了左右子树的前序遍历序列和中序遍历序列,我们也可以用同样的方法分别构建左右子树,也就是说接下来的事情可以用递归的方法去完成。
#include<iostream> #include<vector> using namespace std; struct TreeNode { int val; TreeNode *left; TreeNode *right; TreeNode(int x):val(x), left(NULL),right(NULL){} }; struct TreeNode* reConstructBinaryTree(vector<int> pre, vector<int> in) { if (pre.size() == NULL) return NULL; TreeNode* root = new TreeNode(pre[0]); int i; for (i = 0; i < in.size() && in[i] != pre[0]; i++); vector<int> pre_left, in_left, pre_right, in_right; int pre_i = 1; for (int j = 0; j < in.size(); j++) { if(j< i) { in_left.push_back(in[j]); pre_left.push_back(pre[pre_i]); pre_i++; } else if(j>i) { in_right.push_back(in[j]); pre_right.push_back(pre[pre_i]); pre_i++; } } root->left = reConstructBinaryTree(pre_left, in_left); root->right = reConstructBinaryTree(pre_right, in_right); return root; } void preOrder(TreeNode* root) { if (root == nullptr) return; cout << root->val<<endl; preOrder(root->left); preOrder(root->right); } int main() { vector<int> pre = { 1,2,4,7,3,5,6,8}; vector<int> in = { 4,7,2,1,5,3,8,6}; TreeNode* root = reConstructBinaryTree(pre, in); preOrder(root); system("pause"); }
上述代码需要分配额外的空间,以下代码不需要额外分配空间
#include<iostream> #include<vector> using namespace std; struct TreeNode { int val; TreeNode *left; TreeNode *right; TreeNode(int x):val(x), left(NULL),right(NULL){} }; void preOrder(TreeNode* root) { if (root == nullptr) return; cout << root->val<<endl; preOrder(root->left); preOrder(root->right); } TreeNode* ConstructCore(vector<int> pre, int startPre, int endPre, vector<int> vin, int startIn, int endIn) { int rootValue = pre[startPre]; TreeNode* root = new TreeNode(rootValue); if (startPre == endPre) { if (startIn == endIn && pre[startPre] == vin[startIn]) return root; else throw std::exception("invalid input"); } int rootIn = startIn; while (rootIn <= endIn && vin[rootIn] != rootValue) ++rootIn; if (rootIn == endIn && vin[rootIn] != rootValue) throw std::exception("invalid input"); int leftLength = rootIn - startIn; int leftPreorderEnd = startPre + leftLength; if (leftLength>0) { root->left = ConstructCore(pre, startPre + 1, leftPreorderEnd, vin, startIn, rootIn - 1); } if (leftLength<endPre - startPre) root->right = ConstructCore(pre, leftPreorderEnd + 1, endPre, vin, rootIn + 1, endIn); return root; } TreeNode* reConstructBinaryTree1(vector<int> pre, vector<int> vin) { if (pre.size() == 0 || vin.size() == 0) return nullptr; return ConstructCore(pre, 0, pre.size() - 1, vin, 0, vin.size()-1); } int main() { vector<int> pre = { 1,2,4,7,3,5,6,8}; vector<int> in = { 4,7,2,1,5,3,8,6}; TreeNode* root = reConstructBinaryTree1(pre, in); preOrder(root); system("pause"); }