首先明确题意,宽度是指树的每一层的子树个数,求最大宽度,就是遍历树每一层求最大结点数量。
那么,我们很自然地想到,考虑到树,一般都要通过遍历。而这种特点,毫无疑问与层序遍历相关。
层序遍历逐层地访问树结点,而我们可以在遍历过程中对每一层进行计数,然后找出最大宽度。
由此衍生出了算法,但在具体实施时依旧存在一些细节。比如,我们怎么确定结点对应的层级?怎么统计每一层的结点数?
在进行思考的时候,一开始作为刚刚接触树的小白的我也是一头雾水,在参考了别人的方法与代码后,终于有所体悟。
附上参考的博客:(31条消息) C语言实现的求二叉树的最大宽度(递归与非递归版本)_虎扑最棒的博客-CSDN博客
这篇博客给出的方法很巧妙,但是代码写的较为晦涩,如果不仔细阅读,很难理解很多过程与变量的含义。所以,本人在理解的基础上,自己写了两段代码,尽量简洁易懂,并且在关键步骤进行了标注,希望能对大家有所启迪。
第一段是非递归方法。
int Width_Tree(BiTree T)//非递归的求最大宽度(利用层序遍历)
{
/**************************Begin***************************/
//MAXSIZE是自定义的最大结点数
int count[MAXSIZE];//count数组存储当前层数出现的所有结点数
int width[MAXSIZE];//width数组存储每一层对应的结点数
BiTree queue[MAXSIZE];//队列
for(int k=0;k<MAXSIZE;k++)
{
count[k]=0;
queue[k]=NULL;
width[k]=0;
//在使用前对每个数组进行初始化
}
if(!T)
return 0;//如果为空树,宽度就是0
queue[0]=T;//T首先入队
count[0]=1;//因为存在T,所以至少存在一个结点,count【0】=1
count[1]=1;//count值会随下标index增大而增大,第二层目前默认结点数为0
int index,i,j;
index=1;//index就是count数组的下标,对应不同的层数
i=0,j=0;//i在里面起到了重要的指示作用
while(queue[i])
{
if(queue[i]->lchild)//存在孩子,入队,count值增加
{
j++;
queue[j]=queue[i]->lchild;
count[index]++;
}
if(queue[i]->rchild)//同上
{
j++;
queue[j]=queue[i]->rchild;
count[index]++;
}
i++;//i代表已经遍历过左右孩子的结点,即出队结点
//通过i值才能判断是否跳出该层
if(i>=count[index-1])
index++;//在进入下一层前需要遍历这么多结点,i的比较是index更新的条件
if(count[index]==0)
count[index]+=count[index-1];//更新下一层的count的初值
}
width[0]=1;//第一层只有T一个结点
int u=1;
int max=width[0];//初始化max
while(count[u])
{
width[u]=count[u]-count[u-1];//由count求width
u++;
}
for(int j=1;j<=u;j++)
{
if(max<width[j])
max=width[j];//遍历所有width求max
}
return max;
/**************************End***************************/
}
核心在于count数组的巧妙使用与i指针的移动,它们使我们能够对结点进行对应的分层。
递归版本会涉及两个函数。
第一个是求对应层的宽度(递归方法)。
int Level_Width(BiTree T,int level)//递归求某一层的宽度
{
int width;
if(!T)
return 0;//空树返回0
else
{
if(level==1)//头结点不空且为第一层返回1
return 1;
else
{
width=Level_Width(T->lchild,level-1)+
Level_Width(T->rchild,level-1);
//level层的结点均来自level-1层的结点的左右孩子
return width;
}
}
}
第二个是利用上一个函数求所有层的最大宽度。
int Width(BiTree T)//利用递归方法求最大宽度
{
/**************************Begin***************************/
int width[MAXSIZE];
for(int j=0;j<Depth_Tree(T);j++)
{
width[j]=Level_Width(T,j+1);
}
int max=0;
for(int j=0;j<Depth_Tree(T);j++)
{
if(width[j]>max)
max=width[j];
}
return max;
/**************************End***************************/
}
注意这个函数里我们需要提前知道对应的最大深度(即总层数),那么还可以提供一个求深度的函数。
int Depth_Tree(BiTree T)
{
int depth,d1,d2;
if(!T)
depth=0;
else
{
d1=Depth_Tree(T->lchild);
d2=Depth_Tree(T->rchild);
depth=1+(d1>d2?d1:d2);
}
return depth;
}
典型的递归方法求深度,比较容易理解。