C语言之广度优先算法
广度优先算法又称宽度优先搜索,是一种简便的图的搜索算法之一。搜索方式大致是这样的:
直到搜索到目标结点(结点就是那些圆球球,其中有一个或者多个是目标结点)或者搜完了整个图都没找到目标结点就停止搜索。
实现这个要是想用像深度优先算法那样函数套函数那样是难以实现的(至少我实现不了)。
像这样的:
求问从A到B的最短路径的结点数是多少?
这道题很简单嘛,肯定是A-C-B啊,答案是3啊。那怎样用C语言实现呢?
深搜的话:一条路一条路读取,取结点数最小的,也可以,但是问题来了,当结点数特别多,图非常“辽阔”时,怎么办呢?
用广搜啦!
这里设A的标志为0(这样好些代码嘛),其他的以此类推,所以路径A-C-B就是0-2-1啦
根据路是不是相同的,我们可以创建一个布尔型二维数组way,way[w1][w2]=1代表从w1可以到达w2,=0时则代表不能,注意,因为我们是不会走回头路的,所以所有路都是单向的,比如c->b是可以的,但b->c是不可以的
_Bool way[6][6]={
{0,0,1,1,1,0},
{0,0,0,0,0,0},
{0,1,0,0,0,0},
{0,0,0,0,0,1},
{0,0,0,0,0,1},
{0,1,0,0,0,0},
};
创建一个step数组,初始值为0,step[0]代表A的结点数,step[1]代表B的结点数,因为A只有一个结点所以step[0]=1,储存列出了几层子结点,也就是目前所有路径的结点数
创建一个队列,比如叫que(其实就是个数组嘛)
简单讲下队列的概念:有队首(head)和队尾(tail)两个指针,分别指着队列的第一个元素与最后一个元素。队列只允许从队尾加入队伍,从队首退出队伍。
此时head=tail=0:
在队列que中加入A结点的标志0,步骤是将tail+=1并且que[tail]=0(如图所示)
然后搜索A的子结点,例如这样:
循环(i=0;i<=5;i++)//因为共有6个结点
如果(way[que[head+1]][i]==1)把子结点加入队列;
加入队列的方法就是:
tail+=1;
que[tail]=子结点标志;
注意要让子结点的结点数+=它的父结点的结点数
最后效果如图
当循环完毕以后呢,就等于把A的子结点全找出来了,列出了一整层结点,删去第一个结点,step[2]和[3]和[4]都=step[0]+1,head-=1,那样head指的就是A的子结点C(标志2)了如图
继续判断,搜索2的子结点,并且加入队列,再删去2,搜索3的子结点……直到最后tail指针指的是B(标志1),则输出step[1](B的标志是1),就是最短路径数。如果head=tail了,说明队列为空,而且没找到答案,所以就没有可以到达目标结点的路,输出什么的就随你了。
附上此题答案:
#include <stdio.h> #include <string.h> _Bool way[6][6]={ {0,0,1,1,1,0}, {0,0,0,0,0,0}, {0,1,0,0,0,0}, {0,0,0,0,0,1}, {0,0,0,0,0,1}, {0,1,0,0,0,0}, }; int main() { int que[101],head=0,tail=1,i,step[6]; memset(step,0,sizeof(step));//初始化步数数组 que[1]=0;//初始化队首 step[0]=1; //结点A的步数为1 do { for(i=0;i<=5;i++) { if(way[que[head+1]][i]==1) { tail++; que[tail]=i; step[i]=step[que[head+1]]+1; if(que[tail]==1) { printf("%d",step[1]); return 0; } } } head++; }while(head<tail);//当队列不为空 printf("no answer!"); return 0; }