剑指offer4:重建二叉树(后序遍历)
1. 题目描述
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
2. 思路和方法
(1)先序遍历序列的第一个元素必定是根节点,可以由此获取二叉树的根节点。
(2)根据根节点,中序遍历序列中查找该节点,由中序遍历的性质可知,中序遍历中该根节点左边的序列必定在根节点的左子树中,根节点右边的序列必定在右子树中。由此可以知道先序遍历中左子树以及右子树的起止位置。
(3)分别对左子树和右子树重复上述的过程,直至所有的子树的起止位置相等时,说明已经到达叶子节点,遍历完毕。
(4) 先序+中序->后序,中序+后序->先序,层次+中序->。
例子:
先序遍历: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==)
return NULL;
vector<int> left_pre,right_pre,left_vin,right_vin;
TreeNode* head = new TreeNode(pre[]);
int gen = ;
for(int i=;i<len;i++)
{
if(vin[i]==pre[])
{
gen = i;
break;
}
}
for(int i=;i<gen;i++)
{
left_pre.push_back(pre[i+]);
left_vin.push_back(vin[i]);
}
for(int i=gen+;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 != -)
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() == || pre.size() != vin.size())
return nullptr; TreeNode *newNode = new TreeNode(pre[]);
//如果只剩一个节点了,那么可以直接返回
if (pre.size() == )
return newNode; auto posi = find(vin.begin(), vin.end(), pre[]);
//错误检测
if (posi == vin.end()) {
return nullptr;
}
int leftSize = posi - vin.begin();
int rightSize = vin.end() - posi - ; //递归求解
//这里取前序和后序遍历的左右子树可能有点绕,可以好好思考一下
newNode->left = reConstructBinaryTree(vector<int>(pre.begin() + , pre.begin() + + leftSize),
vector<int>(vin.begin(), vin.begin() + leftSize));
newNode->right = reConstructBinaryTree(vector<int>(pre.begin() + + leftSize, pre.end()),
vector<int>(vin.begin() + leftSize + , vin.end())); return newNode;
} int main()
{
vector<int> pre{ , , , , , , , };
vector<int> vin{ , , , , , , , }; ////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 ;
}
5 扩展
5.1 给出中序和后序,得到二叉树
后序和先序(左右根,根左右),因此后序的根的位置为pos[pos.size()-1].
main函数中的代码如下:
cout << "给出中序和后序,构建二叉树" << endl;
//vector<int> pre{ 1, 2, 4, 7, 3, 5, 6, 8 };
vector<int> vin1{ 4, 7, 2, 1, 5, 3, 8, 6 };
vector<int> pos1{ 7, 4, 2, 5, 8, 6, 3, 1 };
TreeNode* preTraversal = reConstructBinaryTree1(pos1, vin1);
cout << "中序遍历:";
InOrder(preTraversal);
cout << endl;
C++核心代码
TreeNode* reConstructBinaryTree1(vector<int> pos, vector<int> vin)
{
if (pos.size() == || pos.size() != vin.size())
return nullptr; int poslen = pos.size(); TreeNode *newNode = new TreeNode(pos[poslen-]);
//如果只剩一个节点了,那么可以直接返回
if (poslen == )
return newNode; auto posi = find(vin.begin(), vin.end(), pos[poslen-]);
if (posi == vin.end())
return nullptr;
int leftSize = posi - vin.begin();
int rightSize = vin.end() - posi - ; newNode->left = reConstructBinaryTree1(vector<int>(pos.begin(), pos.begin() + leftSize), vector<int>(vin.begin(), vin.begin() + leftSize));
newNode->right = reConstructBinaryTree1(vector<int>(pos.begin() + leftSize, pos.end()-), vector<int>(vin.begin() + leftSize + , vin.end())); return newNode;
}
5.2 给出中序和层次构建二叉树
参考资料:https://blog.csdn.net/yanyanwenmeng/article/details/77833274(一般C++程序)
参考资料:https://blog.csdn.net/sinat_30324577/article/details/82688414(Python)
核心思想: 对于子树,其在层次遍历最前面的点即为根节点,故重建过程包括以下两步:
1.利用层次遍历确定子树的根节点;
2.根据根节点在中序中的位置划定左右子树,递归重建。
一般C++程序
#include<iostream>
#include<string> using namespace std;
string s1, s2;
void calc(int l1, int r1, int l2, int r2)
{
int i, j;
for (i = l2; i <= r2; i++)//找层次遍历中优先输出根节点的位置
{
int b = ;
for (j = l1; j <= r1; j++)
{
if (s2[i] == s1[j])
{
cout << s1[j];//输出根节点
b = ;
break;
}
}
if (b) break;
}
if (j>l1) calc(l1, j - , , r2);//遍历左子树
if (j<r1) calc(j + , r1, , r2);//遍历右子树
}
int main()
{
cin >> s1 >> s2;
calc(, s1.length() - , , s2.length() - );
cout << endl;
return ;
}
运行:输入输出
C++核心程序(vector<int>)
TreeNode* reConstructBinaryTree2(vector<int> level, vector<int> vin)
{
if (level.size() == || vin.size() == )
return nullptr;
vector<int> lst;
for (int i = ; i < vin.size(); i++){
lst.push_back(find(level.begin(), level.end(), vin[i]) - level.begin());
}
int minPosition = min_element(lst.begin(), lst.end()) - lst.begin(); cout << "vin[minPosition]=" << vin[minPosition] << endl;
TreeNode *newNode = new TreeNode(vin[minPosition]); newNode->left = reConstructBinaryTree2(vector<int>(level.begin(), level.end()),
vector<int>(vin.begin(), vin.begin() + minPosition));
newNode->right = reConstructBinaryTree2(vector<int>(level.begin(), level.end()),
vector<int>(vin.begin() + minPosition + , vin.end())); return newNode;
}
输出:
6. 二叉树构建参考资料:用先序构建,https://blog.csdn.net/u014453898/article/details/54894796
C++代码
#include<iostream> #include<string>
using namespace std; /*二叉树的结构体*/
typedef struct BTree
{
int val;
struct BTree *left, *right;
}BTree; /*二叉树的类,包含着操作二叉树的各种方法*/
class Tree
{
public:
BTree *create_node(int level, string pos);
void PreOrder(BTree *t); //先序遍历
void InOrder(BTree *t); //中序遍历
void PostOrder(BTree *t); //后序遍历 BTree *root;
}; /*用先序遍历的方法递归构造一课二叉树*/
BTree* Tree::create_node(int level, string pos)
{
int data;
BTree *node = new BTree; cout << "please enter data:level " << level << " " << pos << endl;
cin >> data; //若输入的数据为0,则把该结点的子结点置为空
if (data == )
{
return NULL;
} node->val = data; /*create_node()的 参数用于在给二叉树赋值时表明
现在赋值的是哪个结点*/
node->left = create_node(level + , "left");
node->right = create_node(level + , "right");
return node;
} void Tree::PreOrder(BTree *t)
{
if (t)
{
cout << t->val << endl;;
PreOrder(t->left);
PreOrder(t->right);
}
} void Tree::InOrder(BTree *t)
{
if (t)
{
InOrder(t->left);
cout << t->val << endl;;
InOrder(t->right);
}
} void Tree::PostOrder(BTree *t)
{
if (t)
{
PostOrder(t->left);
PostOrder(t->right);
cout << t->val << endl;
}
} int main()
{
Tree tree;
tree.root = tree.create_node(, "root");
cout << "Pre" << endl;
tree.PreOrder(tree.root); cout << "In" << endl;
tree.InOrder(tree.root); cout << "Post" << endl;
tree.PostOrder(tree.root); system("pause");
return ;
}
7. 完整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 != -)
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() == || pre.size() != vin.size())
return nullptr; TreeNode *newNode = new TreeNode(pre[]);
//如果只剩一个节点了,那么可以直接返回
if (pre.size() == )
return newNode; auto posi = find(vin.begin(), vin.end(), pre[]); if (posi == vin.end())
return nullptr;
int leftSize = posi - vin.begin();
int rightSize = vin.end() - posi - ; newNode->left = reConstructBinaryTree(vector<int>(pre.begin() + , pre.begin() + + leftSize),
vector<int>(vin.begin(), vin.begin() + leftSize));
newNode->right = reConstructBinaryTree(vector<int>(pre.begin() + + leftSize, pre.end()),
vector<int>(vin.begin() + leftSize + , vin.end())); return newNode;
} TreeNode* reConstructBinaryTree1(vector<int> pos, vector<int> vin)
{
if (pos.size() == || pos.size() != vin.size())
return nullptr; int poslen = pos.size(); TreeNode *newNode = new TreeNode(pos[poslen - ]);
//如果只剩一个节点了,那么可以直接返回
if (poslen == )
return newNode; auto posi = find(vin.begin(), vin.end(), pos[poslen - ]);
if (posi == vin.end())
return nullptr;
int leftSize = posi - vin.begin();
int rightSize = vin.end() - posi - ; newNode->left = reConstructBinaryTree1(vector<int>(pos.begin(), pos.begin() + leftSize), vector<int>(vin.begin(), vin.begin() + leftSize));
newNode->right = reConstructBinaryTree1(vector<int>(pos.begin() + leftSize, pos.end() - ), vector<int>(vin.begin() + leftSize + , vin.end())); return newNode;
} TreeNode* reConstructBinaryTree2(vector<int> level, vector<int> vin)
{
if (level.size() == || vin.size() == )
return nullptr;
vector<int> lst;
for (int i = ; i < vin.size(); i++){
lst.push_back(find(level.begin(), level.end(), vin[i]) - level.begin());
}
int minPosition = min_element(lst.begin(), lst.end()) - lst.begin(); //cout << "vin[minPosition]=" << vin[minPosition] << endl;
TreeNode *newNode = new TreeNode(vin[minPosition]); newNode->left = reConstructBinaryTree2(vector<int>(level.begin(), level.end()),
vector<int>(vin.begin(), vin.begin() + minPosition));
newNode->right = reConstructBinaryTree2(vector<int>(level.begin(), level.end()),
vector<int>(vin.begin() + minPosition + , vin.end())); return newNode;
//if not level or not vin :
//return None
//lst = []
//for num in vin :
// lst.append(level.index(num))
//idx = lst.index(min(lst))
//
//root = TreeNode(vin[idx])
//left = vin[0:idx]
//right = vin[idx + 1:]
//root.left = restruct(level, left)
//root.right = restruct(level, right)
//return root
} int main()
{
//层次遍历是1 2 3 4 5 6 7 8
cout << "给出先序和中序,构建二叉树" << endl;
vector<int> pre0{ , , , , , , , };
vector<int> vin0{ , , , , , , , }; ////7 4 2 5 8 6 3 1 TreeNode* posTraversal = reConstructBinaryTree(pre0, vin0); cout << "后序遍历:";
PostOrder(posTraversal);
cout << endl; cout << "先序遍历:";
PreOrder(posTraversal);
cout << endl; cout << "中序遍历:";
InOrder(posTraversal);
cout << endl; cout << "给出中序和后序,构建二叉树" << endl;
//vector<int> pre{ 1, 2, 4, 7, 3, 5, 6, 8 };
vector<int> vin1{ , , , , , , , };
vector<int> pos1{ , , , , , , , }; TreeNode* preTraversal = reConstructBinaryTree1(pos1, vin1);
cout << "后序遍历:";
PostOrder(preTraversal);
cout << endl; cout << "先序遍历:";
PreOrder(preTraversal);
cout << endl; cout << "中序遍历:";
InOrder(preTraversal);
cout << endl; cout << "给出中序和层次,构建二叉树" << endl;
//vector<int> pre{ 1, 2, 4, 7, 3, 5, 6, 8 };
//vector<int> pos1{ 7, 4, 2, 5, 8, 6, 3, 1 };
vector<int> level2{ , , , , , , , };
vector<int> vin2{ , , , , , , , };
TreeNode* Traversal = reConstructBinaryTree2(level2, vin2);
cout << "后序遍历:";
PostOrder(Traversal);
cout << endl; cout << "先序遍历:";
PreOrder(Traversal);
cout << endl; cout << "中序遍历:";
InOrder(Traversal);
cout << endl; system("pause");
return ;
} //class TreeNode : # 定义二叉树节点类
// def __init__(self, val) :
// self.val = val
// self.left = None
// self.right = None
//
// def restruct(level, vin) :
//if not level or not vin :
//return None
//lst = []
// for num in vin :
// lst.append(level.index(num))
// print("lst" + str(lst))
// idx = lst.index(min(lst))
// print("idx--" + str(idx))
//
// root = TreeNode(vin[idx])
// left = vin[0:idx]
// right = vin[idx + 1:]
// root.left = restruct(level, left)
// root.right = restruct(level, right)
// return root
//
// lst1 = []
// lst2 = []
//
// def pre_traverse(root) :
// if not root :
// return None
// lst1.append(root.val)
// pre_traverse(root.left)
// pre_traverse(root.right)
// return lst1
//
// def leaf(root) :
// if not root :
// return None
// if not root.left and not root.right :
// lst2.append(root.val)
// leaf(root.left)
// leaf(root.right)
// return lst2
//
// b = restruct([1, 2, 3, 4, 5, 6, 7, 8], [4, 7, 2, 1, 5, 3, 8, 6])
//
// print(pre_traverse(b))
参考资料
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
https://blog.csdn.net/u014453898/article/details/54894796
https://blog.csdn.net/u014453898/article/details/54894796
https://blog.csdn.net/sinat_30324577/article/details/82688414
剑指offer4:重建二叉树(后序遍历)的更多相关文章
- 剑指Offer-4.重建二叉树(C++/Java)
题目: 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2 ...
- 剑指offer--二叉树的后序遍历
思路:对于一个二叉树的后序遍历序列来说,最后一个数一定是根节点,然后前面的数中,从最开始到第一个大于根节点的数都是左子树中的数,而后面到倒数第二个数应该都是大于根节点的,是右子树,如果后面的数中有小于 ...
- 剑指offer--4.重建二叉树
题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2, ...
- 二叉树后序遍历的非递归算法(C语言)
首先非常感谢‘hicjiajia’的博文:二叉树后序遍历(非递归) 这篇随笔开启我的博客进程,成为万千程序员中的一员,坚持走到更远! 折磨了我一下午的后序遍历中午得到解决,关键在于标记右子树是否被访问 ...
- 剑指Offer的学习笔记(C#篇)-- 平衡二叉树(二叉树后序遍历递归详解版)
题目描述 输入一棵二叉树,判断该二叉树是否是平衡二叉树. 一 . 题目分析 首先要理解一个概念:什么是平衡二叉树,如果某二叉树中任意的左右子树深度相差不超过1,那么他就是一颗平衡二叉树.如下图: 所以 ...
- 剑指Offer——重建二叉树2
Question 输入某二叉树的后序遍历和中序遍历的结果,请重建出该二叉树.假设输入的后序遍历和中序遍历的结果中都不含重复的数字.例如输入后序遍历序列{1, 3, 4, 2}和中序遍历序列{1, 2, ...
- lintcode.68 二叉树后序遍历
二叉树的后序遍历 描述 笔记 数据 评测 给出一棵二叉树,返回其节点值的后序遍历. 您在真实的面试中是否遇到过这个题? Yes 样例 给出一棵二叉树 {1,#,2,3}, 1 \ 2 / 3 返 ...
- LeetCode:145_Binary Tree Postorder Traversal | 二叉树后序遍历 | Hard
题目:Binary Tree Postorder Traversal 二叉树的后序遍历,题目要求是采用非递归的方式,这个在上数据结构的课时已经很清楚了,二叉树的非递归遍历不管采用何种方式,都需要用到栈 ...
- [Leetcode] Binary tree postorder traversal二叉树后序遍历
Given a binary tree, return the postorder traversal of its nodes' values. For example:Given binary t ...
- 数据结构实验之求二叉树后序遍历和层次遍历(SDUT 2137)
Problem Description 已知一棵二叉树的前序遍历和中序遍历,求二叉树的后序遍历和层序遍历. Input 输入数据有多组,第一行是一个整数t (t<1000),代表有t组测试数据. ...
随机推荐
- kubernetes 的数据的存储 存储卷
根据应用本身是否 需要持久存储数据,以及某一此请求和此前的请求是否有关联性,可以分为四类应用: 1.有状态要存储 2.有状态无持久存储 3.无状态无持久存储4.无状态有持久存储 在k8s上的数据持久性 ...
- Spring+shiro session与线程池的坑
在java web编程中,经常使用shiro来管理session,也确实好用 shiro来获取session的方式 SecurityUtils.getSubject().getSession() 其中 ...
- python并发——进程间同步和通信
一.进程间同步 对于一些临界资源,不能使用并发无限消耗,就需要设置专门的临界标示,比如锁或者信号量等 from multiprocessing import Process, Lock import ...
- 解决Android Studio 升级时提示 Connection failed. Please check your network connection and try again问题
一,问题: 无论mac还是windows可能都会出现这个问题,解决方案大同小异,就是修改VMOptions而已. 解决方案: Windows: 在\Android Studio\bin目录下找到 st ...
- LC 835. Image Overlap
Two images A and B are given, represented as binary, square matrices of the same size. (A binary ma ...
- apache整合tomcat中的一些注意事项
1.整合完毕后,需要把项目同时部署在apache和tomcat中,不然会报错找不到资源 2.可以把tomcat和apcahe的项目路径设置为同一个 3.使用java框架时容易出现异常:The requ ...
- handler四元素
Looper 一个线程可以产生一个Looper对象,由它来管理此线程里的MessageQueue(消息队列). 我们知道一个线程是一段可执行的代码,当可执行代码执行完成后,线程生命周期便会终止,线程就 ...
- C标准库中转换wchar_t和char类型的字符串
C 库函数 - mbstowcs() C 标准库 - <stdlib.h> 描述 C 库函数 size_t mbstowcs(schar_t *pwcs, const char *str ...
- 用mongodump以及mongorestore来完成mongo的迁移任务
首先粘贴官网说明: 详细请见:https://docs.mongodb.com/manual/ 在实际操作中,一般只需用到 mongodump -h ip:port -d dbName -o path ...
- Redis安装与配置( Windows10 )
本文链接:https://blog.csdn.net/gaokcl/article/details/82814134linux安装参考:https://blog.csdn.net/gaokcl/art ...