[模板] 二叉树 由先序遍历和中序遍历建树
蓝桥杯练习系统 试题 算法训练 绘制地图
资源限制
时间限制:1.0s 内存限制:256.0MB
关于二叉树:
【模板】 二叉树_WalkingSeason的博客
问题描述
最近,WYF正准备参观他的点卡工厂。WYF集团的经理氰垃圾需要帮助WYF设计参“观”路线。现在,氰垃圾知道一下几件事情:
- WYF的点卡工厂构成一颗二叉树。
- 一共有n座工厂。
- 他需要把这颗树上的点以后序遍历的方法列出来,才能绘制地图。
还好,最近他的属下给了他先序遍历和中序遍历的数据。可是,氰垃圾最近还要帮㊎澤穻解决一些问题,没时间。请你帮帮他,替他完成这项任务。由于氰垃圾的一些特殊的要求,WYF的参观路线将会是这棵树的后序遍历。
输入格式
第一行一个整数n,表示一共又n座工厂。
第二行n个整数,表示先序遍历。
第三行n个整数,表示中序遍历。
输出格式
输出共一行,包含n个整数,为后序遍历。
样例输入 | 样例输出 |
---|---|
8 1 2 4 5 7 3 6 8 4 2 7 5 1 8 6 3 | 4 7 5 2 8 6 3 1 |
数据规模和约定
0<n<100000,。保证先序遍历和中序遍历合法,且均为1~n。
思路
本题难点在于需要使用前序遍历和中序遍历生成一个二叉树。
参考:中序,先序生成树算法 - holoblog - ITeye博客
算法思想很简单,在先序中的第一个节点一定是根节点,此节点在中序中的位置可以将中序分为左右两棵子树。如:
根为A,中序分为:HDIBJEK A LFMCNGO,这两棵子树在使用同样的方法就生成一棵树。
即递归的思想:
取前序序列的第一个值,即为这个树的根节点,在中序序列中找到这个节点,它两边的序列即是两个子树序列。多次对子树进行上述过程即可。
对于中序序列的拆分即是取该元素两边的序列,这即是子树的中序序列。
对于前序序列:拆分后左子树的中序序列共有a个元素,右子树的中序序列有b个元素,那么从根节点+1至根节点向后的a个即为左子树部分的前序序列,从根节点向后的a+1个至先序序列的末尾即为右子树部分的前序序列。
详见生成二叉树的代码:
//cpp
#include <cstdio>
int makeTree(btree tree,//根据前序序列,中序序列生成后序序列
const int *pre_begin, const int *pre_end, //前序序列范围
const int *in_begin, const int *in_end) //中序序列范围
{
if (pre_end < pre_begin || in_end < in_begin)
return 0; //0表示无效节点
int thisnode = *pre_begin;
const int *index = find(in_begin, in_end, thisnode); //thisnode在中序序列中的地址
//中序序列切分(左子树)
int leftson = makeTree(tree,
pre_begin + 1, pre_begin + (index - in_begin), //左子树前序序列范围
in_begin, index - 1); //左子树中序序列范围
if (leftson) //0表示无效节点
tree.setLeftSon(thisnode, leftson);
//中序序列切分(右子树)
int rightson = makeTree(tree,
pre_begin + (index - in_begin) + 1, pre_end, //左子树前序序列范围
index + 1, in_end); //右子树中序序列范围
if (rightson) //0表示无效节点
tree.setRightSon(thisnode, rightson);
return thisnode;
}
int main()
{
int n, *preOrder, *inOrder;
scanf("%d", &n);
btree *tr = new btree(n);
preOrder = new int[n](), inOrder = new int[n]();
for (int it = 0; it < n; it++)
scanf("%d", preOrder + it);
for (int it = 0; it < n; it++)
scanf("%d", inOrder + it);
tr->setroot(*preOrder);
makeTree(*tr, preOrder, preOrder + n - 1, inOrder, inOrder + n - 1);
vector<int> *v = tr->postOrder();
for (auto it : *v)
printf("%d ", it);
return 0;
}
注意到第8行使用了STL中的find()函数,时间复杂度为O(n),把时间浪费在了寻找中序遍历的节点上了。
我们来做一个优化:输入时记录中序遍历的节点地址,在寻找中先序遍历的节点位置时直接调用即可。
//cpp
int makeTree(btree tree,//根据前序序列,中序序列生成后序序列
const int *pre_begin, const int *pre_end, //前序序列范围
const int *in_begin, const int *in_end, //中序序列范围
const int **fastinorder)/*inorder寻址加速*/
{
if (pre_end < pre_begin || in_end < in_begin)
return 0; //0表示无效节点
int thisnode = *pre_begin;
//const int *index = find(in_begin, in_end, thisnode); //thisnode在中序序列中的地址
const int *index = fastinorder[thisnode];/*inorder寻址加速*/
//中序序列切分(左子树)
int leftson = makeTree(tree,
pre_begin + 1, pre_begin + (index - in_begin), //左子树前序序列范围
in_begin, index - 1, //左子树中序序列范围
fastinorder);/*inorder寻址加速*/
if (leftson) //0表示无效节点
tree.setLeftSon(thisnode, leftson);
//中序序列切分(右子树)
int rightson = makeTree(tree,
pre_begin + (index - in_begin) + 1, pre_end, //左子树前序序列范围
index + 1, in_end, //右子树中序序列范围
fastinorder);/*inorder寻址加速*/
if (rightson) //0表示无效节点
tree.setRightSon(thisnode, rightson);
return thisnode;
}
int main()
{
int n, *preOrder, *inOrder;
int **fastinorder;/*inorder寻址加速*/
scanf("%d", &n);
btree *tr = new btree(n);
preOrder = new int[n](), inOrder = new int[n]();
fastinorder = new int*[n+2]();/*inorder寻址加速*/
for (int it = 0; it < n; it++)
scanf("%d", preOrder + it);
for (int it = 0; it < n; it++){
scanf("%d", inOrder + it);
fastinorder[*(inOrder + it)]=inOrder + it;/*inorder寻址加速*/
}
tr->setroot(*preOrder);
makeTree(*tr, preOrder, preOrder + n - 1, inOrder, inOrder + n - 1, (const int **)fastinorder);/*inorder寻址加速*/
vector<int> *v = tr->postOrder();
for (auto it : *v)
printf("%d ", it);
return 0;
}
//java
import java.util.*;
public class Main {
public static int makeTree(btree tree, // 根据前序序列,中序序列生成后序序列
int[] preorder, final int pre_begin, final int pre_end, // 前序序列范围
int[] inorder, final int in_begin, final int in_end, // 中序序列范围
final int[] fastinorder)/* inorder寻址加速 */
{
if (pre_end < pre_begin || in_end < in_begin)
return 0; // 0表示无效节点
int thisnode = preorder[pre_begin];
final int index = fastinorder[thisnode];/* inorder寻址加速 */
// 中序序列切分(左子树)
int leftson = makeTree(tree,
preorder, pre_begin + 1, pre_begin + index - in_begin, // 左子树前序序列范围
inorder, in_begin, index - 1, // 左子树中序序列范围
fastinorder);/* inorder寻址加速 */
if (leftson != 0) // 0表示无效节点
tree.setLeftSon(thisnode, leftson);
// 中序序列切分(右子树)
int rightson = makeTree(tree,
preorder, pre_begin + index - in_begin + 1, pre_end, // 左子树前序序列范围
inorder, index + 1, in_end, // 右子树中序序列范围
fastinorder);/* inorder寻址加速 */
if (rightson != 0) // 0表示无效节点
tree.setRightSon(thisnode, rightson);
return thisnode;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n, preOrder[], inOrder[];
int fastinorder[];/* inorder寻址加速 */
n = sc.nextInt();
btree tr = new btree(n);
preOrder = new int[n];
inOrder = new int[n];
fastinorder = new int[n + 2];/* inorder寻址加速 */
for (int it = 0; it < n; it++)
preOrder[it] = sc.nextInt();
for (int it = 0; it < n; it++) {
inOrder[it] = sc.nextInt();
fastinorder[inOrder[it]] = it;/* inorder寻址加速 */
}
tr.setroot(preOrder[0]);
makeTree(tr, preOrder, 0, n - 1, inOrder, 0, n - 1, fastinorder);/* inorder寻址加速 */
Vector<Integer> v = tr.postOrder();
for (Integer it : v)
System.out.printf("%d ", it);
}
}
完整代码
//cpp
#include <iostream>
#include <vector>
#include <algorithm> //find()
using namespace std;
struct btree_node
{
int depth;
btree_node *father, *lson, *rson;
};
struct btree
{
btree_node *btree_base;
btree_node *root;
btree(const int &size)
{
btree_base = new btree_node[size + 2]();
}
void setroot(const int &num)//设定树的根节点
{
root = &btree_base[num];
root->depth = 1;
}
bool setLeftSon(const int &this_num, const int &lson_num)
{
btree_node *this_node = &btree_base[this_num],
*lson_node = &btree_base[lson_num];
if (this_node->lson == NULL)
{
this_node->lson = lson_node;
lson_node->father = this_node;
lson_node->depth = this_node->depth + 1;
return true;
}
return false;
}
bool setRightSon(const int &this_num, const int &rson_num)
{
btree_node *this_node = &btree_base[this_num],
*rson_node = &btree_base[rson_num];
if (this_node->rson == NULL)
{
this_node->rson = rson_node;
rson_node->father = this_node;
rson_node->depth = this_node->depth + 1;
return true;
}
return false;
}
bool setFather(const int &this_num, const int &father_num)
{
btree_node *this_node = &btree_base[this_num],
*father_node = &btree_base[father_num];
if (this_node->father == NULL)
{
this_node->father = father_node;
father_node->father = this_node;
father_node->depth = this_node->depth - 1;
return true;
}
return false;
}
int depth(const int &num){
return btree_base[num].depth;
}
void __pre_order(vector<int> &v, btree_node *node)
{
if (node != NULL)
{
v.push_back(node - btree_base);
__pre_order(v, node->lson);
__pre_order(v, node->rson);
}
}
vector<int> *preOrder()//求先序遍历
{
vector<int> *v_preorder = new vector<int>();
__pre_order(*v_preorder, root);
return v_preorder;
}
void __in_order(vector<int> &v, btree_node *node)
{
if (node != NULL)
{
__in_order(v, node->lson);
v.push_back(node - btree_base);
__in_order(v, node->rson);
}
}
vector<int> *inOrder()//求中序遍历
{
vector<int> *v_inorder = new vector<int>();
__in_order(*v_inorder, root);
return v_inorder;
}
void __post_order(vector<int> &v, btree_node *node)
{
if (node != NULL)
{
__post_order(v, node->lson);
__post_order(v, node->rson);
v.push_back(node - btree_base);
}
}
vector<int> *postOrder()//求后序遍历
{
vector<int> *v_postorder = new vector<int>();
__post_order(*v_postorder, root);
return v_postorder;
}
};
int makeTree(btree tree,//根据前序序列,中序序列生成后序序列
const int *pre_begin, const int *pre_end, //前序序列范围
const int *in_begin, const int *in_end, //中序序列范围
const int **fastinorder)/*inorder寻址加速*/
{
if (pre_end < pre_begin || in_end < in_begin)
return 0; //0表示无效节点
int thisnode = *pre_begin;
//const int *index = find(in_begin, in_end, thisnode); //thisnode在中序序列中的地址
const int *index = fastinorder[thisnode];/*inorder寻址加速*/
//中序序列切分(左子树)
int leftson = makeTree(tree,
pre_begin + 1, pre_begin + (index - in_begin), //左子树前序序列范围
in_begin, index - 1, //左子树中序序列范围
fastinorder);/*inorder寻址加速*/
if (leftson) //0表示无效节点
tree.setLeftSon(thisnode, leftson);
//中序序列切分(右子树)
int rightson = makeTree(tree,
pre_begin + (index - in_begin) + 1, pre_end, //左子树前序序列范围
index + 1, in_end, //右子树中序序列范围
fastinorder);/*inorder寻址加速*/
if (rightson) //0表示无效节点
tree.setRightSon(thisnode, rightson);
return thisnode;
}
int main()
{
int n, *preOrder, *inOrder;
int **fastinorder;/*inorder寻址加速*/
scanf("%d", &n);
btree *tr = new btree(n);
preOrder = new int[n](), inOrder = new int[n]();
fastinorder = new int*[n+2]();/*inorder寻址加速*/
for (int it = 0; it < n; it++)
scanf("%d", preOrder + it);
for (int it = 0; it < n; it++){
scanf("%d", inOrder + it);
fastinorder[*(inOrder + it)]=inOrder + it;/*inorder寻址加速*/
}
tr->setroot(*preOrder);
makeTree(*tr, preOrder, preOrder + n - 1, inOrder, inOrder + n - 1, (const int **)fastinorder);/*inorder寻址加速*/
vector<int> *v = tr->postOrder();
for (auto it : *v)
printf("%d ", it);
return 0;
}
//java
import java.util.*;
class btree_node {
public int depth, num;
public btree_node father, lson, rson;
};
class btree {
btree_node[] btree_base;
btree_node root;
public btree(final int size) {
btree_base = new btree_node[size + 2];
for (int i = 1; i <= size; i++) {
btree_base[i] = new btree_node();
btree_base[i].num = i;
}
}
public void setroot(final int num)// 设定树的根节点
{
root = btree_base[num];
root.depth = 1;
}
public boolean setLeftSon(final int this_num, final int lson_num) {
btree_node this_node = btree_base[this_num], lson_node = btree_base[lson_num];
if (this_node.lson == null) {
this_node.lson = lson_node;
lson_node.father = this_node;
lson_node.depth = this_node.depth + 1;
return true;
}
return false;
}
public boolean setRightSon(final int this_num, final int rson_num) {
btree_node this_node = btree_base[this_num], rson_node = btree_base[rson_num];
if (this_node.rson == null) {
this_node.rson = rson_node;
rson_node.father = this_node;
rson_node.depth = this_node.depth + 1;
return true;
}
return false;
}
public boolean setFather(final int this_num, final int father_num) {
btree_node this_node = btree_base[this_num], father_node = btree_base[father_num];
if (this_node.father == null) {
this_node.father = father_node;
father_node.father = this_node;
father_node.depth = this_node.depth - 1;
return true;
}
return false;
}
public int depth(final int num) {
return btree_base[num].depth;
}
void __pre_order(Vector v, btree_node node) {
if (node != null) {
v.add(node.num);
__pre_order(v, node.lson);
__pre_order(v, node.rson);
}
}
public Vector preOrder()// 求先序遍历
{
Vector v_preorder = new Vector();
__pre_order(v_preorder, root);
return v_preorder;
}
void __in_order(Vector v, btree_node node) {
if (node != null) {
__in_order(v, node.lson);
v.add(node.num);
__in_order(v, node.rson);
}
}
public Vector inOrder()// 求中序遍历
{
Vector v_inorder = new Vector();
__in_order(v_inorder, root);
return v_inorder;
}
void __post_order(Vector v, btree_node node) {
if (node != null) {
__post_order(v, node.lson);
__post_order(v, node.rson);
v.add(node.num);
}
}
public Vector postOrder()// 求后序遍历
{
Vector v_postorder = new Vector();
__post_order(v_postorder, root);
return v_postorder;
}
};
public class Main {
public static int makeTree(btree tree, // 根据前序序列,中序序列生成后序序列
int[] preorder, final int pre_begin, final int pre_end, // 前序序列范围
int[] inorder, final int in_begin, final int in_end, // 中序序列范围
final int[] fastinorder)/* inorder寻址加速 */
{
if (pre_end < pre_begin || in_end < in_begin)
return 0; // 0表示无效节点
int thisnode = preorder[pre_begin];
final int index = fastinorder[thisnode];/* inorder寻址加速 */
// 中序序列切分(左子树)
int leftson = makeTree(tree,
preorder, pre_begin + 1, pre_begin + index - in_begin, // 左子树前序序列范围
inorder, in_begin, index - 1, // 左子树中序序列范围
fastinorder);/* inorder寻址加速 */
if (leftson != 0) // 0表示无效节点
tree.setLeftSon(thisnode, leftson);
// 中序序列切分(右子树)
int rightson = makeTree(tree,
preorder, pre_begin + index - in_begin + 1, pre_end, // 左子树前序序列范围
inorder, index + 1, in_end, // 右子树中序序列范围
fastinorder);/* inorder寻址加速 */
if (rightson != 0) // 0表示无效节点
tree.setRightSon(thisnode, rightson);
return thisnode;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n, preOrder[], inOrder[];
int fastinorder[];/* inorder寻址加速 */
n = sc.nextInt();
btree tr = new btree(n);
preOrder = new int[n];
inOrder = new int[n];
fastinorder = new int[n + 2];/* inorder寻址加速 */
for (int it = 0; it < n; it++)
preOrder[it] = sc.nextInt();
for (int it = 0; it < n; it++) {
inOrder[it] = sc.nextInt();
fastinorder[inOrder[it]] = it;/* inorder寻址加速 */
}
tr.setroot(preOrder[0]);
makeTree(tr, preOrder, 0, n - 1, inOrder, 0, n - 1, fastinorder);/* inorder寻址加速 */
Vector<Integer> v = tr.postOrder();
for (Integer it : v)
System.out.printf("%d ", it);
}
}
优化前后: