2024王道408数据结构 P144 T14
思考过程
- 首先看题目,要求我们计算一棵二叉树的最大宽度,也就是结点最多的那一层的结点个数,很适合用层次遍历+辅助队列来实现。
- 每个结点还需要一个level值用来放结点的层数。
举个例子
层次遍历
- 首先we need a 队列q,队列需要有头尾指针,将他们初始化为-1
q.f = q.r = -1;
,还需要一个指针p来存放出队的结点,还有一个变量k用来出队结点的层数。假设二叉树长这个样子 - 首先我们先把头结点给入队,
q.data[++q.r]=b;
并且把level赋值为1,表示该结点在第一层q.level[q.r]=1;
- 将头结点入队之后我们开始进入循环,循环条件是
q.f < q.r
头指针一定要比尾指针小。进入循环的第一件事就是把此时的队尾元素出队,出队的同时用刚刚我们建立好的指针p来存放出队元素的值,p = q.data[++q.f]
注意这里出队要移动队首指针f。出队之后就要判断该结点是否有左孩子和右孩子,如果有的话就入队,q.data[++q.r]=p->lchild;q.level[q.r]=k+1;
,注意这里很关键,入队的这个结点的层数要等于刚刚那个出队结点的层数+1,一定要理解这个地方,是该题的关键。 之后有右孩子也一样入队,也一样把右子树的level值赋为k+1,在例子中也就是把B和C入队,
到这里我们就完成了一次循环。我把每个元素的k值也标在队列上面。其实这里的出队并不完全算是出队,只能算是把队首指针f往后移动了。 - 循环往复知道二叉树中的全部结点都入队了,此时队列中应该是
循环一直出队,直到f指针和r指针相等退出循环。
计算每一层结点个数的最大值
- 那么现在我们所有结点都已经在队列当中了,我们需要变量n用来存放每个结点个数的值,max用来更新最大值,i用来遍历这个队列,此时k我们已经用完了,把它赋值为1表示我们从第一层开始遍历。
- 循环条件是
i <= q.r
i是从0开始遍历的,也就是从A结点开始往后移动,那么它肯定不能大于队尾指针。进入循环后先把n赋值为0,默认每一层有0个结点,然后进入第二层循环就是去计算n的值的,循环条件是q.level[i]==k
当结点的level值和k值相等就表示该层有一个结点,就让n++,同时也让i++。比如例子中,现在k的值为1,结点A的level值也为1,那么表示第一层有一个结点,让n++。 - n++之后还要判断更新max
if(n>max) max = n;
- 遍历完第一层之后还要把k的值也更新为
k = q.level[i]
下一层。比如上面这个例子中第二层遍历完之后n就为2,此时把max的值也更新为2。然后再去遍历下一层。这题就做完了。
完整代码
//
// Created by 黎圣 on 2023/8/21.
//
/*
* 假设二叉树采用二叉链表存储结构,设计一个算法,求非空二叉树b的宽度
* (即具有结点数最多的那一层的结点个数。)
*/
#include "iostream"
typedef struct TreeNode
{
char data;
struct TreeNode *lchild, *rchild;
}*tree;
struct Queue
{
tree data[10];
int f, r;
int level[10];
};
void CreateTree(tree &t)
{
char ch = getchar();
if (ch == '#')
t = NULL;
else
{
t = (struct TreeNode *)malloc(sizeof(struct TreeNode));
t->data = ch;
t->lchild = NULL;
t->rchild = NULL;
CreateTree(t->lchild);
CreateTree(t->rchild);
}
}
int width(tree b)
{
//辅助队列q
Queue q;
//指针p用来存放出队的元素
struct TreeNode *p;
//k用来记录出队结点的层次
int k;
//初始化队列
q.r = q.f = -1;
//入队根结点
q.data[++q.r] = b;
q.level[q.r] = 1;
//层次遍历
while (q.f < q.r)
{
//出队
p = q.data[++q.f];
k = q.level[q.f];
if (p->lchild)
{
q.data[++q.r] = p->lchild;
//进入队列的结点的层次为刚刚出队结点的层次+1
q.level[q.r] = k + 1;
}
if (p->rchild)
{
q.data[++q.r] = p->rchild;
q.level[q.r] = k + 1;
}
}
//n用来记录每层的个数,max用来更新n的最大值,用i遍历队列
int n, max = 0, i = 0;
//此时元素已经全部入队了,k用来从第一层开始
k = 1;
while (i <= q.r)
{
//每层默认有0个结点
n = 0;
while (i <= q.r && q.level[i] == k)
{
//这一层的结点个数+1
n++;
i++;
}
//更新k的值让k去下一层
k = q.level[i];
if (n > max)
max = n;
}
return max;
}
int main()
{
tree t;
CreateTree(t);
//ABD##E##CF##G##
printf("%d", width(t));
return 0;
}
/*
A
B C
D E F G
*/
这题我觉得也挺难的😭,最后感谢b站up主@吸血小金鱼