剑指offer4:重建二叉树(后序遍历)
作者:互联网
1. 题目描述
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
2. 思路和方法
(1)先序遍历序列的第一个元素必定是根节点,可以由此获取二叉树的根节点。
(2)根据根节点,在中序遍历序列中查找该节点,由中序遍历的性质可知,中序遍历中该根节点左边的序列必定在根节点的左子树中,而根节点右边的序列必定在右子树中。由此可以知道先序遍历中左子树以及右子树的起止位置。
(3)分别对左子树和右子树重复上述的过程,直至所有的子树的起止位置相等时,说明已经到达叶子节点,遍历完毕。
例子:
前序遍历:1 2 4 5 7 8 3 6 (根左右)
中序遍历:4 2 7 5 8 1 3 6(左根右)
后序遍历:4 7 8 5 2 6 3 1(左右根)
层次遍历:1 2 3 4 5 6 7 8 (共4层,与广度搜索一样,即广度遍历)
特殊例子:
前序遍历:1, 2, 4, 7, 3, 5, 6, 8 (根左右)
中序遍历:4, 7, 2, 1, 5, 3, 8, 6 (左根右)
后序遍历:7 4 2 5 8 6 3 1(左右根)
层次遍历:1 2 3 4 5 6 7 8 (共4层,与广度搜索一样,即广度遍历)
3. 核心代码
/** * Definition for binary tree * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ class Solution { public: TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) { int len=vin.size(); if (len==0) return NULL; vector<int> left_pre,right_pre,left_vin,right_vin; TreeNode* head = new TreeNode(pre[0]); int gen = 0; for(int i=0;i<len;i++) { if(vin[i]==pre[0]) { gen = i; break; } } for(int i=0;i<gen;i++) { left_pre.push_back(pre[i+1]); left_vin.push_back(vin[i]); } for(int i=gen+1;i<len;i++) { right_pre.push_back(pre[i]); right_vin.push_back(vin[i]); } head->left = reConstructBinaryTree(left_pre,left_vin); head->right = reConstructBinaryTree(right_pre,right_vin); return head; } };
4. C++完整实现
#include <vector>
#include <iostream>
#include <string>
#include <stdlib.h>
#include <algorithm>
using namespace std;
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) :val(x), left(nullptr), right(nullptr) {}
} ;
//打印节点/访问函数
void PrintNode(TreeNode* T)
{
if (T->val != -1)
cout << T->val << " ";
}
//先序遍历
void PreOrder(TreeNode* T)
{
if (T != NULL)
{
//访问根节点
PrintNode(T);
//访问左子结点
PreOrder(T->left);
//访问右子结点
PreOrder(T->right);
}
}
//中序遍历
void InOrder(TreeNode* T)
{
if (T != NULL)
{
//访问左子结点
InOrder(T->left);
//访问根节点
PrintNode(T);
//访问右子结点
InOrder(T->right);
}
}
//后序遍历
void PostOrder(TreeNode* T)
{
if (T != NULL)
{
//访问左子结点
PostOrder(T->left);
//访问右子结点
PostOrder(T->right);
//访问根节点
PrintNode(T);
}
}
TreeNode* reConstructBinaryTree(vector<int> pre, vector<int> vin)
{
if (pre.size() == 0 || pre.size() != vin.size())
return nullptr;
TreeNode *newNode = new TreeNode(pre[0]);
//如果只剩一个节点了,那么可以直接返回
if (pre.size() == 1)
return newNode;
auto posi = find(vin.begin(), vin.end(), pre[0]);
//错误检测
if (posi == vin.end()) {
return nullptr;
}
int leftSize = posi - vin.begin();
int rightSize = vin.end() - posi - 1;
//递归求解
//这里取前序和后序遍历的左右子树可能有点绕,可以好好思考一下
newNode->left = reConstructBinaryTree(vector<int>(pre.begin() + 1, pre.begin() + 1 + leftSize),
vector<int>(vin.begin(), vin.begin() + leftSize));
newNode->right = reConstructBinaryTree(vector<int>(pre.begin() + 1 + leftSize, pre.end()),
vector<int>(vin.begin() + leftSize + 1, vin.end()));
return newNode;
}
int main()
{
vector<int> pre{ 1, 2, 4, 7, 3, 5, 6, 8 };
vector<int> vin{ 4, 7, 2, 1, 5, 3, 8, 6 }; ////7 4 2 5 8 6 3 1
TreeNode *posTraversal = reConstructBinaryTree(pre, vin);
cout << "后序遍历:";
PostOrder(posTraversal);
cout << endl;
cout << "先序遍历:";
PreOrder(posTraversal);
cout << endl;
cout << "先序遍历:";
InOrder(posTraversal);
cout << endl;
system("pause");
return 0;
}
参考资料
https://blog.csdn.net/My_Jobs/article/details/43451187
https://blog.csdn.net/wtyvhreal/article/details/45644843
https://blog.csdn.net/m0_37950361/article/details/82531649
标签:pre,遍历,TreeNode,vin,right,offer4,二叉树,left 来源: https://blog.csdn.net/qq_31965863/article/details/100900094