[模板] 二叉树 由先序遍历和中序遍历建树 & 蓝桥杯练习系统 试题 绘制地图

[模板] 二叉树 由先序遍历和中序遍历建树

蓝桥杯练习系统 试题 算法训练 绘制地图

蓝桥杯练习系统 试题 算法训练 绘制地图

资源限制

时间限制: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);
	}
}

优化前后:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值