BFS广度优先搜索算法详解与实现
概括:广度优先是优先搜索所有相邻的节点,再访问所有相邻节点的邻节点。
算法描述:从图的某一结点出发,首先依次访问该结点对的所有邻接顶点,再按这些顶点被访问的先后次序依次访问与它们相邻接的所有未被访问的顶点,重复此过程,直至所有顶点均被访问为止。
预备知识
队列详解及其实现:
https://blog.csdn.net/ASCIIdragon/article/details/84675299
邻接表详解及其实现:
https://blog.csdn.net/ASCIIdragon/article/details/84635236
c语言实现代码
/** 邻接表深度优先遍历和广度优先遍历 **/
#include<stdio.h>
#include<stdlib.h>
#define MaxVex 255
#define TRUE 1
#define FALSE 0
typedef int VertexType; //顶点类型
typedef int Bool;
Bool visited[MaxVex]; //全局数组,记录图中节点访问状态
typedef struct EdgeNode { //边表节点
int adjvex; //该邻接点在顶点数组中的下标
struct EdgeNode *next; //链域 指向下一个邻接点
}EdgeNode;
typedef struct VertexNode { //头节点
VertexType data; //顶点信息
EdgeNode *firstedge; //边表头指针(指向第一条依附于该顶点的弧的指针)
}VertexNode,AdjList[MaxVex]; //顶点数组(结构体数组)
typedef struct Graph{
AdjList adjList;
int numVertexes,numEdges; //图中当前的结点数以及边数
}Graph,*GraphAdjList;
/** 队列定义及相关操作(广度遍历会用到此循环队列) **/
typedef struct LoopQueue{
int data[MaxVex];
int front,rear;
}LoopQueue,*Queue; //队列结构
void initQueue(Queue &Q){
Q->front=Q->rear=0;
}
Bool QueueEmpty(Queue &Q){
if(Q->front == Q->rear){
return TRUE;
}else{
return FALSE;
}
}
Bool QueueFull(Queue &Q){
if((Q->rear+1)%MaxVex == Q->front){
return TRUE;
}else{
return FALSE;
}
}
/**
* 队尾插入元素
*/
void EnQueue(Queue &Q,int e){
if(!QueueFull(Q)){
Q->data[Q->rear] = e;
Q->rear = (Q->rear+1)%MaxVex;
}
}
/**
* 队头删除元素
*/
void DeQueue(Queue &Q,int *e){
if(!QueueEmpty(Q)){
*e = Q->data[Q->front];
Q->front = (Q->front+1)%MaxVex;
}
}
/*************************************************/
/**
* 图的广度优先遍历
*/
void BFSTraverse(GraphAdjList &G){
int i;
Queue Q = (Queue)malloc(sizeof(LoopQueue));
for (i=0; i<G->numVertexes; ++i){
visited[i] = FALSE; //初始将visited数组都设置为0,因为目前还没有访问任何节点
}
initQueue(Q); 初始化队列
for (i=0; i<G->numVertexes; ++i){ //依次遍历整个图的结点
if(!visited[i]){ //如果这个顶点已经访问过了,就换下一个顶点
visited[i] = TRUE; //如果没访问过,将这个节点标记为已经访问过了
printf("%d ", G->adjList[i].data); //并将该顶点输出
EnQueue(Q, i); //然后,将该节顶点放到队列当中
while (!QueueEmpty(Q)){ //如果队列不为空
DeQueue(Q, &i); //将i这个顶点从队列中删除。
EdgeNode *p = G->adjList[i].firstedge; //p指向该顶点的邻接点
while (p){ //如果顶点还有没访问的邻接点,进入循环体,如果已经都访问完了,判断队列是否为空
if (!visited[p->adjvex]){ //如果这个邻接点记录过了, 跳到 p = p->next,p向后移动,指向其他邻接点
visited[p->adjvex] = TRUE; //如果这个边表节点没记录过,将这个节点记录为已经访问过
printf("%d ", G->adjList[p->adjvex].data); //打印这个节点保存的数据
EnQueue(Q, p->adjvex); //将这个节点放到队列中
}
p = p->next; //p向后移动,指向其他邻接点
}
}
}
}
}
参考博客:
https://blog.csdn.net/lxl121181/article/details/73300700
https://blog.csdn.net/leo881205/article/details/80358401
https://www.cnblogs.com/kubixuesheng/p/4399705.htm