二叉树的整合
树
树有 nnn 个节点,并且只有 n−1n-1n−1 条边连接所有的点,保证所有点联通,也就是没有环。
比如:

整理后可以得到上图这样一个形状。
然后标上层数。

对于点 xxx 来说层数小于点 xxx 并且有边与之相连的点只会有一个,这个点被称为点 xxx 的父亲节点,而点 xxx 成为这个点的子节点。
没有子节点的点称为叶子结点。
没有父亲节点的点称为树的根节点。
二叉树定义及概念
首先它是一棵树,并且对于每一个点,它最多只有两个子节点。
比如:

然后有几个概念。
满二叉树
一颗二叉树,除了叶子结点外,其他的点都有两个子节点,并且叶子结点都在同一层。
就像这样:

性质:
- 一颗 nnn 层的满二叉树一共有 2n−12^n-12n−1 个节点。
- 一颗满二叉树的第 iii 层有 2i−12^{i-1}2i−1 个节点。
- 一颗有 nnn 个节点的满二叉树的深度为 log2(n+1)\log_2(n+1)log2(n+1)
完全二叉树
可以理解为一颗满二叉树,从最右边的叶子结点开始,依次删去叶子结点。

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

先序遍历
按照 根 −-− 左 −-− 右的顺序遍历整棵树。(根指当前点,左指当前点的左子节点,右指当前点的右子节点)
上面树的先序遍历是:1−2−4−6−3−5−7−81-2-4-6-3-5-7-81−2−4−6−3−5−7−8。
先序遍历中,根节点是第一个元素。
中序遍历
按照 左 −-− 根 −-− 右的顺序遍历整棵树。
上面树的中序遍历是:6−4−2−1−7−5−8−36-4-2-1-7-5-8-36−4−2−1−7−5−8−3。
中序遍历中,一个点的左子树上所有的点在其左,右子树上点在其右。
后序遍历
按照 根 −-− 左 −-− 右的顺序遍历整棵树。
上面树的后序遍历是:6−4−2−7−8−5−3−16-4-2-7-8-5-3-16−4−2−7−8−5−3−1。
后序遍历中,根节点是最后一个元素。
实现
存储
可以考虑用一个结构体来存。
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+5−2+6∗2∗(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 + × +
浙公网安备 33010602011771号