二叉树求最大宽度(C语言实现)

首先明确题意,宽度是指树的每一层的子树个数,求最大宽度,就是遍历树每一层求最大结点数量。

那么,我们很自然地想到,考虑到树,一般都要通过遍历。而这种特点,毫无疑问与层序遍历相关。

层序遍历逐层地访问树结点,而我们可以在遍历过程中对每一层进行计数,然后找出最大宽度。

由此衍生出了算法,但在具体实施时依旧存在一些细节。比如,我们怎么确定结点对应的层级?怎么统计每一层的结点数?

在进行思考的时候,一开始作为刚刚接触树的小白的我也是一头雾水,在参考了别人的方法与代码后,终于有所体悟。

附上参考的博客:(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;
}

典型的递归方法求深度,比较容易理解。

  • 5
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

向前进吧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值