文章目录
题目描述
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如,给出
- 前序遍历 preorder = [3,9,20,15,7]
- 中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
题解思路
方法一:迭代
在先序遍历中,前后紧邻的两个节点a和b,在树中的位置有三种情况:
- b是a的左子树节点(父子关系),对应a有左子树
- b是a的右子树节点(父子关系),对应a没有左子树,但有右子树
- b是a的某个有右子树的祖父节点,对应a既没有左子树,也没有右子树
因为在前序遍历中,a的祖父节点和祖父节点的左子树绝不可能在a的后面。
在中序遍历中,前后紧邻的两个节点a和b,在树中的位置有两种情况:
- b是a的右子树中的最左侧节点,对应a有右子树(在a右子树只有一个节点的情况下,退化为b是a的右节点)
- a是b的左子树中的最右侧节点,对应a没有右子树(在b的左子树只有一个节点的情况下,退化为a是b的左节点)
代码实现:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if(preorder.size() != preorder.size() || preorder.size() == 0) return nullptr;
TreeNode* root = new TreeNode(preorder[0]); // 创建根节点,并标记
TreeNode* cur = root; // 正在确定位置的节点
stack<TreeNode*> s;
for(int i = 1, j = 0; i < preorder.size(); ++i) {
// 有左子树的情况,一直沿左子树深入,并将沿途节点放入栈中
if (cur->val != inorder[j]) { // inorder[j]代表最左节点(除已经确定左子树的节点)
cur->left = new TreeNode(preorder[i]);
s.push(cur);
cur = cur->left;
}
else { // 没有左子树的情况
j++;
while (!s.empty() && s.top()->val == inorder[j]) { // 栈顶是其父节点,判断有无右子树
cur = s.top(); // 没有右子树,就追溯到有右节点的祖父节点
s.pop();
j++;
}
cur->right = new TreeNode(preorder[i]); // preorder[i]即当前节点的右子树节点,并且下次从右子树开始遍历
cur = cur->right;
}
}
return root;
}
};
方法二:递归
在二叉树的前序遍历序列中,第一个数字总是树的根结点的值。但在中序遍历序列中,根结点的值在序列的中间,左子树的结点的值位于根结点的值的左边,而右子树的结点的值位于根结点的值的右边。因此我们需要扫描中序遍历序列,才能找到根结点的值。
前序遍历序列的第一个数字1就是根结点的值。扫描中序遍历序列,就能确定根结点的值的位置。根据中序遍历特点,在根结点的值1前面的3个数字都是左子树结点的值,位于1后面的数字都是右子树结点的值。
在二叉树的前序遍历和中序遍历的序列中确定根结点的值、左子树结点的值和右子树结点的值的步骤如下图所示:
分别找到了左、右子树的前序遍历序列和中序遍历序列,我们就可以用同样的方法分别去构建左右子树。换句话说,这是一个递归的过程。
代码实现
BinaryTreeNode* ConstructCore(int* startPreorder, int* endPreorder, int* startInorder, int* endInorder){
BinaryTreeNode* root = new BinaryTreeNode();
int rootValue = startPreorder[0];
root->m_value = rootValue;
root->m_right = root->m_left = NULL;
if(startPreorder == endPreorder){
if(startInorder == endInorder && *startPreorder == *startInorder) return root;
else {
try{
throw std::exception();
}
catch(...){
cout << "Invalid input." << endl;
}
}
}
else{
int* rootInorder = startInorder;
while(rootInorder < endInorder && *rootInorder != rootValue) ++rootInorder;
if(rootInorder == endInorder && *rootInorder != rootValue) {
try{
throw std::exception();
}
catch(...){
cout << "Invalid input." << endl;
}
}
int leftLength = rootInorder - startInorder;
int* leftPreorderEnd = startPreorder + leftLength;
if(leftLength > 0){
// 构建左子树
root->m_left = ConstructCore(startPreorder + 1, leftPreorderEnd, startInorder, rootInorder-1);
}
if(leftLength < endPreorder - startPreorder){
// 构建右子树
root->m_right = ConstructCore(leftPreorderEnd + 1, endPreorder, rootInorder+1, endInorder);
}
}
return root;
}
BinaryTreeNode* Construct(int* preorder, int* inorder, int length){
if(preorder == nullptr || inorder == nullptr || length <= 0) return nullptr;
return ConstructCore(preorder, preorder+length-1, inorder, inorder+length-1);
}
代码测试:
#include <iostream>
#include <queue>
using namespace std;
struct BinaryTreeNode{
int m_value;
BinaryTreeNode * m_left;
BinaryTreeNode * m_right;
};
BinaryTreeNode* ConstructCore(int* startPreorder, int* endPreorder, int* startInorder, int* endInorder){
BinaryTreeNode* root = new BinaryTreeNode();
int rootValue = startPreorder[0];
root->m_value = rootValue;
root->m_right = root->m_left = NULL;
if(startPreorder == endPreorder){
if(startInorder == endInorder && *startPreorder == *startInorder) return root;
else {
try{
throw std::exception();
}
catch(...){
cout << "Invalid input." << endl;
}
}
}
else{
int* rootInorder = startInorder;
while(rootInorder < endInorder && *rootInorder != rootValue) ++rootInorder;
if(rootInorder == endInorder && *rootInorder != rootValue) {
try{
throw std::exception();
}
catch(...){
cout << "Invalid input." << endl;
}
}
int leftLength = rootInorder - startInorder;
int* leftPreorderEnd = startPreorder + leftLength;
if(leftLength > 0){
// 构建左子树
root->m_left = ConstructCore(startPreorder + 1, leftPreorderEnd, startInorder, rootInorder-1);
}
if(leftLength < endPreorder - startPreorder){
// 构建右子树
root->m_right = ConstructCore(leftPreorderEnd + 1, endPreorder, rootInorder+1, endInorder);
}
}
return root;
}
BinaryTreeNode* Construct(int* preorder, int* inorder, int length){
if(preorder == nullptr || inorder == nullptr || length <= 0) return nullptr;
return ConstructCore(preorder, preorder+length-1, inorder, inorder+length-1);
}
// 层序遍历
void BinaryTreeLevelOrder(BinaryTreeNode * root){
queue<BinaryTreeNode*> qu;
qu.push(root);
BinaryTreeNode* cur;
while(!qu.empty()){
cur = qu.front();
cout << cur->m_value << ' ';
if(cur->m_left) qu.push(cur->m_left);
if(cur->m_right) qu.push(cur->m_right);
qu.pop();
}
}
int main(){
/*
int preorder[] = {1, 2, 4, 7, 3, 5, 6, 8}; // 前序遍历
int inorder[] = {4, 7, 2, 1, 5, 3, 8, 6}; // 中序遍历
BinaryTreeNode * root = Construct(preorder, inorder, 8);*/
int preorder[] = {1, 2, 3, 4, 5};
int inorder[] = {1, 2, 3, 4, 5};
BinaryTreeNode * root = Construct(preorder, inorder, 5);
BinaryTreeLevelOrder(root);
return 0;
}
代码实现图:
如有不同见解,欢迎留言讨论~~~