二叉树的整合

树有 nnn 个节点,并且只有 n−1n-1n1 条边连接所有的点,保证所有点联通,也就是没有环。
比如:
在这里插入图片描述
整理后可以得到上图这样一个形状。
然后标上层数。
树
对于点 xxx 来说层数小于点 xxx 并且有边与之相连的点只会有一个,这个点被称为点 xxx 的父亲节点,而点 xxx 成为这个点的子节点。
没有子节点的点称为叶子结点。
没有父亲节点的点称为树的根节点。

二叉树定义及概念

首先它是一棵树,并且对于每一个点,它最多只有两个子节点。
比如:
在这里插入图片描述
然后有几个概念。
满二叉树
一颗二叉树,除了叶子结点外,其他的点都有两个子节点,并且叶子结点都在同一层。
就像这样:
在这里插入图片描述

性质:

  1. 一颗 nnn 层的满二叉树一共有 2n−12^n-12n1 个节点。
  2. 一颗满二叉树的第 iii 层有 2i−12^{i-1}2i1 个节点。
  3. 一颗有 nnn 个节点的满二叉树的深度为 log⁡2(n+1)\log_2(n+1)log2(n+1)

完全二叉树
可以理解为一颗满二叉树,从最右边的叶子结点开始,依次删去叶子结点。
在这里插入图片描述

二叉树的遍历

所有的遍历都从根节点开始。
下面有一棵树:
tree

先序遍历
按照 根 −-−- 右的顺序遍历整棵树。(根指当前点,左指当前点的左子节点,右指当前点的右子节点)
上面树的先序遍历是:1−2−4−6−3−5−7−81-2-4-6-3-5-7-812463578
先序遍历中,根节点是第一个元素。
中序遍历
按照 左 −-−- 右的顺序遍历整棵树。
上面树的中序遍历是:6−4−2−1−7−5−8−36-4-2-1-7-5-8-364217583
中序遍历中,一个点的左子树上所有的点在其左,右子树上点在其右。
后序遍历
按照 根 −-−- 右的顺序遍历整棵树。
上面树的后序遍历是:6−4−2−7−8−5−3−16-4-2-7-8-5-3-164278531
后序遍历中,根节点是最后一个元素。

实现

存储
可以考虑用一个结构体来存。

struct node{
	int l,r;
}tree[N];

如果有值:

struct node{
	int x,l,r;
}tree[N];

找根
生面说过,没爹的就是根节点,所以只用找到没有父节点的点就行了,一棵树中保证只有一个根节点。
遍历

void first(int x){
	if(x){
		print(x),psp;
		first(f[x].l);
		first(f[x].r);
	}
}
void mid(int x){
	if(x){
		mid(f[x].l);
		print(x),psp;
		mid(f[x].r);
	}
}
void last(int x){
	if(x){
		last(f[x].l);
		last(f[x].r);
		print(x),psp;
	}
}

例题

题目描述
输入一棵二叉树的先序和中序遍历,输出其后序遍历序列。
输入格式
共两行,第1行一个字符串,表示树的先序遍历,第二行一个字符串,表示树的中序遍历。树的节点一律用小写字母表示。
输出格式
仅一行,表示树的后序遍历。

需要根据上面遍历的各自性质来求。
因为先序遍历中,第一个一定是根节点,以此类推,在先序遍历中越靠前的,就是越上层的点,越靠近根。

在后序遍历中,根节点是最后输出的。

按照先序遍历,遍历完根节点第二个点就是根节点左子树的根。那么这个点就是倒数第二个输出的……以此类推。

我们考虑每次在先序遍历中往后找一个点,然后在中序遍历中找到这个点的左右子树,然后重复这个操作。

#include<bits/stdc++.h>
#define endl putchar('\n')
#define psp putchar(' ')
using namespace std;
int read(){
	int x=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();};
	while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+c-'0',c=getchar();
	return x*f;
}
void print(int x){
	if(x<0)putchar('-'),x=-x;
	if(x<10){putchar(x+'0');return;}
	print(x/10);
	putchar(x%10+'0');
}
int n,m,k;
int T;
int len;
string first,mid;
void dfs(int l,int r){
	bool flag=0;
	for(int i=0;i<len;i++){
		for(int j=l;j<=r;j++){
			if(mid[j]==first[i]){
				dfs(l,j-1);//遍历左子树
				dfs(j+1,r);//遍历右子树
				cout<<mid[j];//后序遍历越靠前的点越后面输出。
				flag=1;//找到就溜
				break;
			}
		}
		if(flag)break;
	}
}
signed main(){
	cin>>first>>mid;
	len=mid.size();
	dfs(0,len-1);
}

其他

二叉树还有另一个用处。
比如我们有一颗这样的树。
在这里插入图片描述
我们对他进行中序遍历,就可以得到一个算式。
1+5−2+6∗2∗(1+1) 1+5-2+6*2*(1+1) 1+52+62(1+1)
在对他进行先序遍历,就可以得到上面算式的前缀表达式:
+ − + 1 5 2 ×× 6 2 + 1 1 +\ -\ +\ 1\ 5\ 2\ \times\times\ 6\ 2\ +\ 1\ 1 +  + 1 5 2 ×× 6 2 + 1 1
同样的,对他进行后序遍历就可以得到上面算是的后缀表达式:
1 5 + 2 − 6 2 × 1 1 + × + 1\ 5\ +\ 2\ -\ 6\ 2\ \times\ 1\ 1\ +\ \times\ + 1 5 + 2  6 2 × 1 1 + × +

posted on 2025-07-21 19:54  fish2012  阅读(19)  评论(0)    收藏  举报  来源