[模板] 二叉樹 & 用先序遍歷和中序遍歷建樹 (藍橋杯練習系統 演算法訓練 繪製地圖)
[模板] 二叉樹
該模板實現以下功能:
前序遍歷,中序遍歷,後序遍歷,詢問節點深度
關於樹的基礎知識參考深入學習二叉樹(一) 二叉樹基礎 - 簡書
//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);
}
}
優化前後: