广度优先搜索(邻接矩阵)
1.1一、用数组来存放顶点
vexs[0] = ‘A’
vexs[1] = ‘B’
vexs[2] = ‘C’
vexs[3] = ‘D’
vexs[4] = ‘E’
vexs[5] = ‘F’
vexs[6] = ‘G’
vexs[7] = ‘H’
vexs[8] = ‘I’
1.2、用邻接矩阵来表示边
上面这个矩阵中,0表示每个顶点没有到达自己的路径。1表示两个顶点之间有路径,无穷大表示两个顶点之间没有路径。
假如按照程序计数习惯,行或列都从0数起。
第0行第0列为0,表示A到它本身之间没有路径(这是人为规定的,因为A到它自身不需要路径)。
第0行第1列为1,表示顶点A和B之间有路径。
第0行第5列为1,表示顶点A和顶点F之间有路径。
第0行其他列为无穷大,表示A到其它点之间没有路径。
……
因为是无向图,邻接矩阵必然有两个特点:
① 对角线(左上角到右下角)上的元素值全为0.表示每个点到它自身没有(或不需要)路径。
② 其它的元素关于对角线对称。
如果不同的顶点之间没有路径,也是用0来表示,则邻接矩阵为
上面的邻接矩阵,在编程时可以用二维数组来实现:
arc[0][1] = arc[1][0] = 1;
arc[0][5] = arc[5][0] = 1;
arc[1][2] = arc[2][1] = 1;
arc[1][6] = arc[6][1] = 1;
arc[1][8] = arc[8][1] = 1;
arc[2][3] = arc[3][2] = 1;
arc[2][8] = arc[8][2] = 1;
arc[3][4] = arc[4][3] = 1;
arc[3][6] = arc[6][3] = 1;
arc[3][7] = arc[7][3] = 1;
arc[3][8] = arc[8][3] = 1;
arc[4][5] = arc[5][4] = 1;
arc[4][7] = arc[7][4] = 1;
arc[5][6] = arc[6][5] = 1;
arc[6][7] = arc[7][6] = 1;
1.3 广度优先遍历
广度优先遍历需要借助于另外的数据结构队列。当把图中的顶点放到队列中时,表示这个顶点被遍历了(可以把顶点的值打印出来)。
用图1中的右图来分析广度优先遍历更方便,因为右图的层次结构更明显。
起初,把点A放入队列中,A被遍历。如上图中的(1)所示。
接着把队首元素A出队,把A的下一层的顶点B和F移进队列,B和F被遍历。如上图中的(2)所示。
队首元素B出队,B的下一层顶点C,G,I相继入队,C、G和I被遍历。如上图中的(3)所示。
队首元素F出队,F的下一层顶点E入队,E被遍历。如上图中的(5)所示。
队首元素C出队,C的下一层顶点D入队,D被遍历。如上图中的(6)所示。
队首元素G出队,G的下一层有两个顶点:D和H。D已在队列里,H入队,H被遍历。如上图中的(4)所示。
队首元素I出队,I的下一层顶点D已在队列里,没有新顶点入队。如上图中的(7)所示。
队首元素E出队,E的下一层顶点D和H都已在队列里,没有新顶点入队。如上图中的(8)所示。
队首元素D出队,D没有下一层顶点,所以没有新顶点入队。如上图中的(9)所示。
队首元素H出队,H没有下一层顶点,所以没有新顶点入队。此时队列为空,遍历结束。
最终,广度优先遍历的顺序即入队列(或出队列)的顺序:A B F C G I E D H
2.1 邻接矩阵生成
#define MAX_VEX_NUM 20
typedef char VertextType;
typedef enum { DG, UDG }GraphKind; //判定图的类型,有向或无向
typedef struct
{
VertextType vexs[MAX_VEX_NUM]; //存放结点的char行数组
int arcs[MAX_VEX_NUM][MAX_VEX_NUM]; //存放边的数组
int vexnum, arcnum;//结点数,边数
GraphKind Type;//存放图的类型
}MGraph;
//索引判断
int index(char vex, MGraph* mg)
{
int i;
for (i = 1;i <= mg->vexnum;i++)
{
if (mg->vexs[i] == vex)
return i;
}
return 0;
}
//生成邻接矩阵
void Creat_MG(MGraph* mg)
{
int type, i, j, k, v1_index, v2_index;
char v1, v2;
printf("please input graph type 0.DG 1.UDG. input nums:");
scanf_s("%d", &type); //输入图的类型
if (type == 0)
mg->Type = DG;
else if (type == 1)
{
mg->Type = UDG;
}
else
{
printf("please input 0 or 1!!!");
return;
}
printf("Please input vexnum:");
scanf_s("%d", &mg->vexnum); //输入结点数
printf("Please input arcnum:");
scanf_s("%d", &mg->arcnum);//输入边数
getchar();
for (i = 1;i <= mg->vexnum;i++)
{
printf("please input %d vex:", i);
scanf_s("%c", &mg->vexs[i],1);//循环存放每个结点
getchar();
}
for (i = 1;i <= mg->vexnum;i++)
for (j = 1;j <= mg->vexnum;j++)
mg->arcs[i][j] = 0;//初始化边,全部设为0
for (k = 1;k <= mg->arcnum;k++)
{
printf("Please input %d arc(vex1,vex2):", k);
scanf_s("%c %c", &v1,1, &v2,1);
v1_index = index(v1, mg);//索引该结点对应的位置
v2_index = index(v2, mg);//索引该结点对应的位置
if (mg->Type == 1)//如果是无向图
{
mg->arcs[v1_index][v2_index] = 1;
mg->arcs[v2_index][v1_index] = 1;//将矩阵的对应的值1
}
else
mg->arcs[v1_index][v2_index] = 1;
getchar();
}
}
void Print_MG(MGraph* mg)
{
int i, j;
if (mg->Type == 0)
printf("Is Direct Graph\n");
else
printf("Is UNDirect Graph\n");
for (i = 1;i <= mg->vexnum;i++)
{
for (j = 1;j <= mg->vexnum;j++)
{
printf("%d ", mg->arcs[i][j]);//遍历输出矩阵
}
printf("\n");
}
}
2.1创建队列
#define M 50
//循环队列的结构类型定义
typedef int DataType;
typedef struct
{
DataType sequ[M];
int rear, quelen;
}Queue;
//建立队
Queue* creatQueue()
{
Queue* sq;
sq = (Queue*)malloc(sizeof(Queue));
return sq;
}
//置空队
void InitQueue(Queue* sq)
{
sq->rear = M - 1;
sq->quelen = 0;
}
//入队
void QueueIn(Queue* sq, DataType x)
{
if (sq->quelen == 50)
printf("Errot! The queue will be overflow! \n");
else if ((sq->rear + 1) == M)
{
sq->rear = (sq->rear + 1) % M;
sq->sequ[sq->rear] = x;
sq->quelen++;
}
else
{
sq->rear++;
sq->sequ[sq->rear] = x;
sq->quelen++;
}
}
//出队
DataType QueueOut(Queue* sq)
{
DataType sun = 0;
if (sq->quelen == 0)
{
printf("Error! The queue will be under flow!\n");
return 0;
}
else if ((sq->rear + 1) >= sq->quelen)
{
sq->quelen--;
sun = sq->sequ[sq->rear - sq->quelen];
return(sun);
}
else
{
sq->quelen--;
sun = sq->sequ[sq->rear - sq->quelen + M];
return(sun);
}
}
//判断队列是否为空
int Empty(Queue* sq)
{
if (sq->quelen == 0)
{
printf("Error! The queue will be under flow!\n");
return 0;
}
return 1;
}
2.3 BFS算法
//BFS算法实现思路1
void BFsTraverse(MGraph G)
{
int i, j , v = 0;
Queue *Q = creatQueue();
InitQueue(Q);
int visited[100];
for ( i = 0; i <= G.vexnum; i++)
{
visited[i] = 0;
}
for ( i = 1; i <= G.vexnum; i++)
{
if (!visited[i])
{
printf("%c", G.vexs[i]);
visited[i] = 1;
//返问过入队
QueueIn(Q , i);
while (!Q)
{
//出队
v = QueueOut(Q);
//出队的同时将该节点的邻接边(弧)入队
for (j = 1; j <= G.vexnum; j++)
{
if (G.arcs[i][j] == 1 && visited[j] != 1)
{
printf("%c", G.vexs[j]);
visited[j] = 1;
QueueIn(Q, j);
}
}
}
}
}
}
//BFS算法实现思路2
int visited[100] = {0};
void BFS(MGraph G, int v0) //vo搜索起点
{
int i, j, v = 0;
Queue* Q = creatQueue();
InitQueue(Q);
//起点入队
if (!visited[v0])
{
QueueIn(Q, v0);
visited[v0] = 1;
printf("%c", G.vexs[v0]);
while (!Empty(Q))
{
v = QueueOut(Q);
for (j = 1;j <= G.vexnum; j++)
{
if (G.arcs[v][j] == 1 && visited[j] != 1)
{
printf("%c", G.vexs[j]);
visited[j] = 1;
QueueIn(Q, j);
}
}
}
}
//搜索其他树,防止森林其他树为搜索
for (i = 1; i <= G.vexnum; i++)
{
if (visited[i] != 1 )
{
BFS(G, i);
}
}
}
完整代码
#include<stdio.h>
#include<stdlib.h>
#define MAX_VEX_NUM 20 //最大顶点数
#define M 50 //队列长度
typedef char VertextType;
typedef enum { DG, UDG }GraphKind; //判定图的类型,有向或无向
typedef struct
{
VertextType vexs[MAX_VEX_NUM]; //存放结点的char行数组
int arcs[MAX_VEX_NUM][MAX_VEX_NUM]; //存放边的数组
int vexnum, arcnum;//结点数,边数
GraphKind Type;//存放图的类型
}MGraph;
//循环队列的结构类型定义
typedef int DataType;
typedef struct
{
DataType sequ[M];
int rear, quelen;
}Queue;
//建立队
Queue* creatQueue()
{
Queue* sq;
sq = (Queue*)malloc(sizeof(Queue));
return sq;
}
//置空队
void InitQueue(Queue* sq)
{
sq->rear = M - 1;
sq->quelen = 0;
}
//入队
void QueueIn(Queue* sq, DataType x)
{
if (sq->quelen == 50)
printf("Errot! The queue will be overflow! \n");
else if ((sq->rear + 1) == M)
{
sq->rear = (sq->rear + 1) % M;
sq->sequ[sq->rear] = x;
sq->quelen++;
}
else
{
sq->rear++;
sq->sequ[sq->rear] = x;
sq->quelen++;
}
}
//出队
DataType QueueOut(Queue* sq)
{
DataType sun = 0;
if (sq->quelen == 0)
{
printf("Error! The queue will be under flow!\n");
return 0;
}
else if ((sq->rear + 1) >= sq->quelen)
{
sq->quelen--;
sun = sq->sequ[sq->rear - sq->quelen];
return(sun);
}
else
{
sq->quelen--;
sun = sq->sequ[sq->rear - sq->quelen + M];
return(sun);
}
}
//判断队列是否为空
int Empty(Queue* sq)
{
if (sq->quelen == 0)
{
printf("Error! The queue will be under flow!\n");
return 0;
}
return 1;
}
//索引判断
int index(char vex, MGraph* mg)
{
int i;
for (i = 1;i <= mg->vexnum;i++)
{
if (mg->vexs[i] == vex)
return i;
}
return 0;
}
//生成邻接矩阵
void Creat_MG(MGraph* mg)
{
int type, i, j, k, v1_index, v2_index;
char v1, v2;
printf("please input graph type 0.DG 1.UDG. input nums:");
scanf_s("%d", &type); //输入图的类型
if (type == 0)
mg->Type = DG;
else if (type == 1)
{
mg->Type = UDG;
}
else
{
printf("please input 0 or 1!!!");
return;
}
printf("Please input vexnum:");
scanf_s("%d", &mg->vexnum); //输入结点数
printf("Please input arcnum:");
scanf_s("%d", &mg->arcnum);//输入边数
getchar();
for (i = 1;i <= mg->vexnum;i++)
{
printf("please input %d vex:", i);
scanf_s("%c", &mg->vexs[i],1);//循环存放每个结点
getchar();
}
for (i = 1;i <= mg->vexnum;i++)
for (j = 1;j <= mg->vexnum;j++)
mg->arcs[i][j] = 0;//初始化边,全部设为0
for (k = 1;k <= mg->arcnum;k++)
{
printf("Please input %d arc(vex1,vex2):", k);
scanf_s("%c %c", &v1,1, &v2,1);
v1_index = index(v1, mg);//索引该结点对应的位置
v2_index = index(v2, mg);//索引该结点对应的位置
if (mg->Type == 1)//如果是无向图
{
mg->arcs[v1_index][v2_index] = 1;
mg->arcs[v2_index][v1_index] = 1;//将矩阵的对应的值1
}
else
mg->arcs[v1_index][v2_index] = 1;
getchar();
}
}
//BFS算法实现思路1
void BFsTraverse(MGraph G)
{
int i, j , v = 0;
Queue *Q = creatQueue();
InitQueue(Q);
int visited[100];
for ( i = 0; i <= G.vexnum; i++)
{
visited[i] = 0;
}
for ( i = 1; i <= G.vexnum; i++)
{
if (!visited[i])
{
printf("%c", G.vexs[i]);
visited[i] = 1;
//返问过入队
QueueIn(Q , i);
while (!Q)
{
//出队
v = QueueOut(Q);
//出队的同时将该节点的邻接边(弧)入队
for (j = 1; j <= G.vexnum; j++)
{
if (G.arcs[i][j] == 1 && visited[j] != 1)
{
printf("%c", G.vexs[j]);
visited[j] = 1;
QueueIn(Q, j);
}
}
}
}
}
}
//BFS算法实现思路2
int visited[100] = {0};
void BFS(MGraph G, int v0) //vo搜索起点
{
int i, j, v = 0;
Queue* Q = creatQueue();
InitQueue(Q);
//起点入队
if (!visited[v0])
{
QueueIn(Q, v0);
visited[v0] = 1;
printf("%c", G.vexs[v0]);
while (!Empty(Q))
{
v = QueueOut(Q);
for (j = 1;j <= G.vexnum; j++)
{
if (G.arcs[v][j] == 1 && visited[j] != 1)
{
printf("%c", G.vexs[j]);
visited[j] = 1;
QueueIn(Q, j);
}
}
}
}
//搜索其他树,防止森林其他树为搜索
for (i = 1; i <= G.vexnum; i++)
{
if (visited[i] != 1 )
{
BFS(G, i);
}
}
}
void Print_MG(MGraph* mg)
{
int i, j;
if (mg->Type == 0)
printf("Is Direct Graph\n");
else
printf("Is UNDirect Graph\n");
for (i = 1;i <= mg->vexnum;i++)
{
for (j = 1;j <= mg->vexnum;j++)
{
printf("%d ", mg->arcs[i][j]);//遍历输出矩阵
}
printf("\n");
}
}
int main()
{
MGraph MG;
Creat_MG(&MG);
Print_MG(&MG);
printf("BFsTraverse\n");
BFsTraverse(MG);
printf("\nBFS\n");
BFS(MG, 1);
return 0;
}