目录
目的
前言
从前序与中序遍历序列构造二叉树
从中序与后序遍历序列构造二叉树
根据(前序遍历序列+ 中序遍历序列)或者 (中序遍历序列 + 后序遍历序列)构建一颗二叉树。
二叉树前序遍历的顺序为:
先遍历根节点;
随后递归地遍历左子树;
最后递归地遍历右子树。
二叉树中序遍历的顺序为:
先递归地遍历左子树;
随后遍历根节点;
最后递归地遍历右子树。
二叉树后序遍历的顺序为:
先递归地遍历左子树;
随后递归地遍历右子树;
最后遍历根节点。
// 前序遍历
void inorder(TreeNode* root) {
if (root == nullptr) {
return;
}
ans.push_back(root->val);
inorder(root->left);
inorder(root->right);
}
// 中序遍历
void inorder(TreeNode* root) {
if (root == nullptr) {
return;
}
inorder(root->left);
ans.push_back(root->val);
inorder(root->right);
}
// 后序遍历
void postorder(TreeNode* root) {
if (root == nullptr) {
return;
}
postorder(root->left);
postorder(root->right);
ans.push_back(root->val);
}
在「递归」地遍历某个子树的过程中,我们也是将这颗子树看成一颗全新的树,按照上述的顺序进行遍历。挖掘「前序遍历」、「中序遍历」、「后序遍历」的性质,我们就可以构建一颗二叉树。
给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。
对于任意一颗树而言,前序遍历的形式总是
[ 根节点, [左子树的前序遍历结果], [右子树的前序遍历结果] ]
即根节点总是前序遍历中的第一个节点。而中序遍历的形式总是
[ [左子树的中序遍历结果], 根节点, [右子树的中序遍历结果] ]
只要我们在中序遍历中定位到根节点,那么我们就可以分别知道左子树和右子树中的节点数目。由于同一颗子树的前序遍历和中序遍历的长度显然是相同的,因此我们就可以对应到前序遍历的结果中,对上述形式中的所有左右括号进行定位。
这样以来,我们就知道了左子树的前序遍历和中序遍历结果,以及右子树的前序遍历和中序遍历结果,我们就可以递归地对构造出左子树和右子树,再将这两颗子树接到根节点的左右位置。
#include
#include
#include
#include
#include
using namespace std;
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode() : val(0), left(nullptr), right(nullptr) {}
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};
TreeNode* ConstructCore(vector& preorder, vector& inorder,int prestart,int preend,int inorderstart,int inorderend){
if(prestart > preend || inorderstart > inorderend){
return nullptr;
}
// 前序遍历中的第一个节点就是根节点
TreeNode* root = new TreeNode;
root->left = root->right = nullptr;
root->val = preorder[prestart];
if(prestart == preend && inorderstart == inorderend){
return root;
}
// 在中序遍历中定位根节点
int i = 0,k;
for(k = inorderstart ; k <= inorderend ;k++){
if(inorder[k] == preorder[prestart]){
break;
}
i++;
}
// 递归地构造左子树,并连接到根节点
if(i > 0){
root->left = ConstructCore(preorder,inorder,prestart+1,prestart+i,inorderstart,inorderstart + i -1);
}
// 递归地构造右子树,并连接到根节点
if(inorderend - inorderstart+1 - i > 0){
root->right = ConstructCore(preorder,inorder,prestart +i+1,preend,inorderstart+i+1,inorderend);
}
return root;
}
TreeNode* buildTree(vector& preorder, vector& inorder) {
int len = preorder.size();
if(len == 0){
return nullptr;
}
return ConstructCore(preorder,inorder,0,len-1,0,len-1);
}
//打印二叉树
void printfTree(TreeNode* root) {
if (root == nullptr) {
cout << "null" << endl;
return;
}
queue q;
q.push(root);
while (!q.empty()) {
int size = q.size();
for (int i = 0; i < size; i++) {
TreeNode* node = q.front();
q.pop();
if (node != nullptr) {
cout << node->val << " ";
q.push(node->left);
q.push(node->right);
}
else {
cout << "null ";
}
}
cout << endl;
}
}
int main(){
vector preorder = {3,9,20,15,7};
vector inorder = {9,3,15,20,7};
printfTree(buildTree(preorder,inorder));
return 0;
}
运行截图:
给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。
思路:
与前序+中序的思路相似,我们可以发现后序遍历的数组最后一个元素代表的即为根节点。知道这个性质后,我们可以利用已知的根节点信息在中序遍历的数组中找到根节点所在的下标,然后根据其将中序遍历的数组分成左右两部分,左边部分即左子树,右边部分为右子树,针对每个部分可以用同样的方法继续递归下去构造。
#include
#include
#include
#include
#include
using namespace std;
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode() : val(0), left(nullptr), right(nullptr) {}
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};
TreeNode* ConstructCore(vector& postorder, vector& inorder,int p1,int p2,int in1,int in2){
if(p1 > p2 || in1 > in2){
return nullptr;
}
// 后序遍历中的最后个节点就是根节点
TreeNode* root = new TreeNode;
root->left = root->right = nullptr;
root->val = postorder[p2];
// 在中序遍历中定位根节点
int i = 0 , k;
for(k = in1 ; k <= in2 ;k++){
if(inorder[k] == root->val){
break;
}
i++;
}
//返回叶子结点
if(p1 == p2 && in1 == in2){
return root;
}
// 递归地构造左/右子树,并连接到根节点
root->left = ConstructCore(postorder,inorder,p1,p1+i-1,in1,in1+i-1);
root->right = ConstructCore(postorder,inorder,p1+i,p2-1,in1+i+1,in2);
return root;
}
TreeNode* buildTree(vector& postorder, vector& inorder) {
int len = postorder.size();
if(len == 0){
return nullptr;
}
return ConstructCore(postorder,inorder,0,len-1,0,len-1);
}
//打印二叉树
void printfTree(TreeNode* root) {
if (root == nullptr) {
cout << "null" << endl;
return;
}
queue q;
q.push(root);
while (!q.empty()) {
int size = q.size();
for (int i = 0; i < size; i++) {
TreeNode* node = q.front();
q.pop();
if (node != nullptr) {
cout << node->val << " ";
q.push(node->left);
q.push(node->right);
}
else {
cout << "null ";
}
}
cout << endl;
}
}
int main(){
vector inorder = {9,3,15,20,7};
vector postorder = {9,15,7,20,3};
printfTree(buildTree(postorder,inorder));
return 0;
}
运行截图: