1. 程式人生 > 其它 >[模板] 二叉樹 & 用先序遍歷和中序遍歷建樹 (藍橋杯練習系統 演算法訓練 繪製地圖)

[模板] 二叉樹 & 用先序遍歷和中序遍歷建樹 (藍橋杯練習系統 演算法訓練 繪製地圖)

[模板] 二叉樹

  該模板實現以下功能:

  前序遍歷,中序遍歷,後序遍歷,詢問節點深度

  關於樹的基礎知識參考深入學習二叉樹(一) 二叉樹基礎 - 簡書

//cpp
#include <vector>

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; } };
//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;
	}
};

例題:繪製地圖

藍橋杯練習系統 試題 演算法訓練 繪製地圖

資源限制

時間限制:1.0s 記憶體限制:256.0MB

問題描述

  最近,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);
	}
}

優化前後: