前言
不知道在上一篇二叉树从入门到AC(1)构建和前中后序遍历
有没有人察觉一个问题,
在一开始的二叉树构建中,只要输入前序(叶子结点需加0 0)就可以确定一颗二叉树,而后半段又说只有前序和后序遍历无法确定一颗二叉树,这不是矛盾吗?
实际上,这里的代码构建的是满二叉树:
而单纯的前序和后序确实是无法构建唯一二叉树的,因为我们可能会遇到一些特殊情况。
我们来看看下图:
我们来写一下他的前序遍历:
A B DE C FG
我们会发现一个尴尬的情况,对比下图,结构不一样,前序排列居然,完全一样。
所以单一的前序,本身不足以作为构建二叉树的条件,至于为什么前序和后序无法确定唯一二叉树,理由同上,可以多做几组不同的实验很好得出结论。
一、二叉树的深度
首先,二叉树的深度的定义,我们沿用leetcode的定义:
说白了就是一个梗:这波你在第几层,找到在大气层的选手输出层数即可。
那么算法应该很简单就能构思了,我们既然能遍历完这棵二叉树,那么在递归中使用一个MAX始终保存每个叶子结点的深度的最大值即可。
例题:
假设根恒为1号结点,
输入:n,然后n行输入n对儿子结点的编号,叶子结点输入为0。
输出:该二叉树的深度。
例如
Input:
5
2 3
4 5
0 0
0 0
0 0
Output:
4
可以理解为 第i行的两个数,分别为第i号结点的左右子结点
思路:
题意表明第i点的左右子结点编号分别为f[i][0] ,f[i][1]
结构体加DFS遍历
运用结构体储存遍历的两个方向
用DFS的算法思路不停地一插到底。
题解:
#include<stdio.h>
int n, max;
struct node {
int left;
int right;
}BTtree[1000003];//开个足够大的空间
int Max(int a,int b)
{
if(a>b)
return a;
else
return b;
}
void DFS(int id, int deep) {
max = Max(max, deep);//记忆化搜索保留最大值
if (id == 0) return ;//到达叶子结点时停止向下
DFS(BTtree[id].left, deep+1);//向左遍历
DFS(BTtree[id].right, deep+1);//向右遍历
}
int main() {
int i=0;
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d %d",&BTtree[i].left,&BTtree[i].right); //输入该结点的左结点和右结点
}
DFS(1, 1);//从1号结点出发,初始深度为1
printf("%d",max);
return 0;
}
到这里,可以发现,DFS仿佛成为了二叉树的核心算法。事实上,面对一个普通的线性表,我们通常可以用循环处理掉,而二叉树结构天生便与DFS搭档,因为线性表通常不需要DFS,更复杂的图和树会让DFS递归运算时间指数级爆炸,只有二叉树和DFS搭配使用才看起来一切刚刚好!
那么DFS一招鲜足够了吗?其实还有一种遍历,较之前中后序的递归演绎更直观,DFS同时也不再好使:层次遍历。
二、层次遍历
二叉树的层次遍历即按层次,以从上至下从左至右的顺序进行遍历。
以此二叉树为例
层次遍历即:ABCDEFG
这也是最直观好理解的遍历方式。
思路:
与前三种遍历运用的DFS栈式思路不同,这种一层层均匀向外拓展的遍历方式可以让我们想到一个东西:BFS,而BFS与DFS核心的区别便是,BFS则需要使用一个队列来进行维护。
所以在层次遍历中,我们将使用队列为结构。
这边先通俗地解释二者的区别:DFS是栈式思路,到了非叶子结点不会先输出而是往下接着搜索,等到输出这个点时已经一层层return回来了,满足first in last out。而BFS是利用队列先进先出,比如上图,按照层次遍历,读到的就地直接输出了。
具体算法:若该点非叶子结点,输出,将其下一层子结点排入队列。
我们可以模拟一下上图的情况:
队列:1.a入队 并放入子结点b c
2.b入队,放入子结点d e
3.c入队,放入子结点f g
如此反复,按先后顺序输出这个队列,即可得到层次遍历结果。
样例:
输入输出范例:
代码:
#include<stdio.h>
#include<stdlib.h>
typedef struct BTNode
{
int data;
struct BTNode *Left;
struct BTNode *Right;
}Node;
//创建二叉树,按前序输入
Node* createBTree()
{
Node *p;
int ch;
//printf("输入data");
scanf("%d",&ch);
if(ch == 0) //如果到了叶子节点,接下来的左、右子树分别赋值为0
{
p = NULL;
}
else
{
p = (Node*)malloc(sizeof(Node));
p->data = ch;
p->Left = createBTree(); //递归创建左子树
p->Right = createBTree(); //递归创建右子树
}
return p;
}
int main()
{
int i=0, ans[101] ,count=0,k=0,n=1;
int Front = 0, Rear = 1;
Node *root = NULL;
Node *q[101],*v;
root = createBTree();
q[0] = root;
while(Front <Rear){
v= q[Front++];
ans[count++] = v->data;
if(v->Left != NULL) q[Rear++] = v->Left; //把左子结点放入队列
if(v->Right != NULL) q[Rear++] = v->Right;//把右子结点放入队列
}
for(i = 0; i < count; i++)//输出层次遍历
{
k++;
printf("%d ",ans[i]);
if(k==n)//只是美观
{
printf("\n");
n*=2;
k=0;
}
}
return 0;
}