广度优先搜索过程:
(1)从图中的某和顶点v出发,访问v。
(2)依次访问v的各个未曾访问过的邻接点。
(3)从这些邻接点出发依次访问它们的邻接点,并使“先被访问的顶点的邻接点”先于“后被访问的顶点的邻接点”被访问。重复步骤(3),直到图中所有已被访问的顶点的邻接点都被访问到。
算法步骤:
(1)从图中某个顶点v出发,访问v;置visited[v]为true,v入队;
(2)只要队列非空,重复下述操作:
第一:队头顶点u出队;
第二:一次检查u的所有邻接点w,如果visited[w]=false,访问w,并置visited[w]=true,然后将w入队。
当图使用邻接表表示时,算法实现如下:
//采用邻接表表示的图的广度优先搜索
void BFS(ALGraph &G, int v, SQueue &Q){
//访问顶点v
cout<<G.vertices[v].data;
visited[v]=true;
InitQueue(Q);//辅助队列初始化
EnQueue(Q, v);
while(!IsEmptyQueue(Q)){
int u;
DeQueue(Q, u);
//依次访问u的所有邻接点
ArcNode *p;
p=G.vertices[u].firstarc;//p指向u的边链表的第一个边结点
while(p!=NULL){
int w=p->adjvex;
if(!visited[w]){
cout<<G.vertices[w].data;
visited[w]=true;
EnQueue(Q, w);
}
p=p->nextarc;
}
}
}
完整的实现代码如下:
#include<stdio.h>
#include<stack>
#include <iostream>
#define MAXSIZE 100
#define MaxInt 32767 //表示最大值,即正无穷大
#define MVNum 100 //定义最大顶点数
using namespace std;
//========================使用邻接表法表示图============================
typedef char VerTexType; //定义顶点数据类型为字符型
typedef int ArcType; //定义边的权值类型为整型
//定义边结点
typedef struct ArcNode{
int adjvex; //该边所指向顶点的位置
struct ArcNode *nextarc; //指向下一条边的指针
}ArcNode;
//定义顶点结点信息
typedef struct VNode{
VerTexType data;
ArcNode *firstarc; //指向依附于该顶点的边的指针
}VNode, AdjList[MVNum];
//定义连接表结构
typedef struct{
AdjList vertices;
int vexnum, arcnum; //当前图的顶点数和边数
}ALGraph;
bool visited[MVNum]; //访问标志数组,初试为false
//=========================队列的定义和实现===============================
typedef struct{
int *base;//存储基地址
int front;//队头指针
int rear;//队尾指针
}SQueue;
//初始化顺序队列
bool InitQueue(SQueue &Q){
Q.base=new int[MAXSIZE];//分配存储空间
if(!Q.base){
return false;
}
Q.front=Q.rear=0;
return true;
}
//入队
bool EnQueue(SQueue &Q, int e){
if((Q.rear+1)%MAXSIZE==Q.front){
return false;//队满,入队失败
}
Q.base[Q.rear]=e;
Q.rear=(Q.rear+1)%MAXSIZE;
return true;
}
//计算队列长度
int QueueLength(SQueue &Q){
return (Q.rear-Q.front+MAXSIZE)%MAXSIZE;
}
//队列是否为空
bool IsEmptyQueue(SQueue &Q){
return Q.rear==Q.front ? true : false;
}
//出队
bool DeQueue(SQueue &Q, int &e){
if(Q.rear==Q.front){
return false;//队空
}
e=Q.base[Q.front];
Q.front=(Q.front+1)%MAXSIZE;
return true;
}
//==============================图的遍历和创建=================================
//确定顶点vex在G.vertices中的序号
int LocateVex(ALGraph &G, VerTexType vex){
for(int i=0;i<G.vexnum;i++){
if(G.vertices[i].data==vex){
return i;
}
}
}
//邻接表法创建无向图
void CreateUGD(ALGraph &G){
printf("输入总顶点数:");
cin>>G.vexnum;
printf("输入总边数:");
cin>>G.arcnum;
//输入各个顶点,构造邻接表的表头结点表
for(int i=0;i<G.vexnum;i++){
printf("请输入第%d个顶点的信息:", (i+1));
cin>>G.vertices[i].data;
G.vertices[i].firstarc=NULL;
}
//输入各边,构造邻接表
for(int k=0;k<G.arcnum;k++){
printf("请输入第%d条边的信息:\n", (k+1));
printf("请输入边依附的第1个顶点:");
VerTexType v1;
cin>>v1;
printf("请输入边依附的第2个顶点:");
VerTexType v2;
cin>>v2;
//确定v1,v2在图G中的位置,即在G.vertices中的序号
int i=LocateVex(G, v1);
int j=LocateVex(G, v2);
struct ArcNode *p1, *p2;
p1=new ArcNode; //生成一个新的边结点
p1->adjvex=j;
p1->nextarc=G.vertices[i].firstarc;
G.vertices[i].firstarc=p1;
p2=new ArcNode; //生成另一个对称边结点p2
p2->adjvex=i;
p2->nextarc=G.vertices[j].firstarc;
G.vertices[j].firstarc=p2;
}
}
//遍历图的邻接表
void PrintfG(ALGraph &G){
printf("遍历图的邻接表:\n");
for(int i=0;i<G.vexnum;i++){
printf("顶点%c ", G.vertices[i].data);
ArcNode *p;
p=G.vertices[i].firstarc;
while(p){
printf("%d ", p->adjvex);
p=p->nextarc;
}
printf("\n");
}
printf("\n");
}
//采用邻接表表示的图的广度优先搜索
void BFS(ALGraph &G, int v, SQueue &Q){
//访问顶点v
cout<<G.vertices[v].data;
visited[v]=true;
InitQueue(Q);//辅助队列初始化
EnQueue(Q, v);
while(!IsEmptyQueue(Q)){
int u;
DeQueue(Q, u);
//依次访问u的所有邻接点
ArcNode *p;
p=G.vertices[u].firstarc;//p指向u的边链表的第一个边结点
while(p!=NULL){
int w=p->adjvex;
if(!visited[w]){
cout<<G.vertices[w].data;
visited[w]=true;
EnQueue(Q, w);
}
p=p->nextarc;
}
}
}
int main(){
ALGraph G;
SQueue Q;
CreateUGD(G);
PrintfG(G);
//初始化访问数组
for(int i=0;i<MVNum;i++){
visited[i]=false;
}
BFS(G, 0, Q);
}