在采用邻接表存储的无向图的广度优先遍历方式也与采用邻接矩阵存储的方式基本一致,BFS算法每次遍历一个顶点,如果没有被访问就把该顶点加入队列,并标记为已经访问,然后遍历队列,如果队列不为空就把第一个结点出队,然后依次该顶点的全部邻接结点,如果邻接结点没有被访问,就把该邻接结点加入队列并标记为已经访问,如果被访问了就不用管,然后重复看队列里面还有没有元素,有的话重复上述同样的操作继续遍历邻接表,如果队列为空就回到上一层循环,从下一个顶点开始同样的遍历操作。直至邻接表全部遍历完成,对应的广度优先遍历结果就出来了。
我们将创建这个图的邻接表广度优先遍历次序为ABFCGEDH,当然遍历序列情况也是不唯一的根据不同的邻接表储存来决定:
为了方便我就手动输入结点信息创建邻接表,创建邻接表的邻接结点的方式采用单链表中的头插法
邻接表顶点存储的结果:
BFS核心算法代码:
完整代码(包括:邻接表存储、顺序队列实现、BFS算法)
#include<stdio.h>
#include<stdlib.h>
#define MAXVEX 8 // 最大顶点数
#define TRUE 1
#define FALSE 0
typedef char VertexType; // 顶点类型,使用字符表示
typedef int EdgeType; // 边上的权值类型,使用整数表示
typedef int Boolean; // 布尔类型
Boolean visited[MAXVEX]; // 用于记录顶点的访问状态
// 定义顺序队列结构体
typedef struct {
int data[MAXVEX]; // 存储队列元素的数组
int front; // 队列的前端(队首)
int rear; // 队列的后端(队尾)
} SeqQueue;
// 边表结点
typedef struct EdgeNode {
int adjvex; // 顶点下标,表示该边的终点
EdgeType info; // 边上的权值
struct EdgeNode* next; // 指向下一条边的指针
} EdgeNode;
// 顶点结点
typedef struct VertexNode {
VertexType data; // 顶点数据
EdgeNode* first; // 指向该顶点的第一条边
} VertexNode, AdjList[MAXVEX];
// 图的邻接表表示
typedef struct {
AdjList adjList; // 顶点数组
int numNodes; // 图的顶点数
int numEdges; // 图的边数
} GraphAdjList;
// 初始化队列
void InitQueue(SeqQueue* q) {
q->front = 0; // 队列的前端初始化为0
q->rear = 0; // 队列的后端初始化为0
}
// 检查队列是否为空
int QueueIsEmpty(SeqQueue q) {
return q.front == q.rear;
}
// 检查队列是否已满
int IsFull(SeqQueue* q) {
return (q->rear + 1) % MAXVEX == q->front;
}
// 入队操作
int Enqueue(SeqQueue* q, int index) {
if (IsFull(q)) {
printf("Queue is full!\n");
return -1; // 入队失败
}
q->data[q->rear] = index; // 将元素放入队尾
q->rear = (q->rear + 1) % MAXVEX; // 更新队尾指针
return 0; // 入队成功
}
// 出队操作
int Dequeue(SeqQueue* q, int* item) {
if (QueueIsEmpty(*q)) {
printf("Queue is empty!\n");
return -1; // 出队失败
}
*item = q->data[q->front]; // 从队首获取元素
q->front = (q->front + 1) % MAXVEX; // 更新队首指针
return 0; // 出队成功
}
// 打印队列中的所有元素
void PrintQueue(SeqQueue q) {
if (QueueIsEmpty(q)) {
printf("Queue is empty!\n");
return;
}
int i = q.front;
while (i != q.rear) {
printf("%c ", q.data[i]); // 打印队列中的元素
i = (i + 1) % MAXVEX; // 移动到下一个位置
}
printf("\n");
}
void CreateALGraph(GraphAdjList* G) {
int i, j;
EdgeNode* e = NULL;
char str[] = "ABCDEFGH"; // 顶点数据
// 初始化邻接表
for (i = 0; i < G->numNodes; i++) {
G->adjList[i].data = str[i]; // 设置顶点数据
G->adjList[i].first = NULL; // 边表初始化为空
}
// 添加边 A->F
e = (EdgeNode*)malloc(sizeof(EdgeNode));
e->adjvex = 5; // 邻接顶点序号为F
e->next = G->adjList[0].first; // 插入到邻接表的第一个位置
G->adjList[0].first = e;
// 添加边 A->B->F
e = (EdgeNode*)malloc(sizeof(EdgeNode));
e->adjvex = 1; // 邻接顶点序号为B
e->next = G->adjList[0].first;
G->adjList[0].first = e;
// 添加边 B->A->C->G
e = (EdgeNode*)malloc(sizeof(EdgeNode));
e->adjvex = 6; // 邻接顶点序号为G
e->next = G->adjList[1].first;
G->adjList[1].first = e;
e = (EdgeNode*)malloc(sizeof(EdgeNode));
e->adjvex = 2; // 邻接顶点序号为C
e->next = G->adjList[1].first;
G->adjList[1].first = e;
e = (EdgeNode*)malloc(sizeof(EdgeNode));
e->adjvex = 0; // 邻接顶点序号为A
e->next = G->adjList[1].first;
G->adjList[1].first = e;
// 添加边 C->B->D
e = (EdgeNode*)malloc(sizeof(EdgeNode));
e->adjvex = 3; // 邻接顶点序号为D
e->next = G->adjList[2].first;
G->adjList[2].first = e;
e = (EdgeNode*)malloc(sizeof(EdgeNode));
e->adjvex = 1; // 邻接顶点序号为B
e->next = G->adjList[2].first;
G->adjList[2].first = e;
// 添加边 D->C->H
e = (EdgeNode*)malloc(sizeof(EdgeNode));
e->adjvex = 7; // 邻接顶点序号为H
e->next = G->adjList[3].first;
G->adjList[3].first = e;
e = (EdgeNode*)malloc(sizeof(EdgeNode));
e->adjvex = 2; // 邻接顶点序号为C
e->next = G->adjList[3].first;
G->adjList[3].first = e;
// 添加边 E->F->H
e = (EdgeNode*)malloc(sizeof(EdgeNode));
e->adjvex = 7; // 邻接顶点序号为H
e->next = G->adjList[4].first;
G->adjList[4].first = e;
e = (EdgeNode*)malloc(sizeof(EdgeNode));
e->adjvex = 5; // 邻接顶点序号为F
e->next = G->adjList[4].first;
G->adjList[4].first = e;
// 添加边 F->A->E->G
e = (EdgeNode*)malloc(sizeof(EdgeNode));
e->adjvex = 6; // 邻接顶点序号为G
e->next = G->adjList[5].first;
G->adjList[5].first = e;
e = (EdgeNode*)malloc(sizeof(EdgeNode));
e->adjvex = 4; // 邻接顶点序号为E
e->next = G->adjList[5].first;
G->adjList[5].first = e;
e = (EdgeNode*)malloc(sizeof(EdgeNode));
e->adjvex = 0; // 邻接顶点序号为A
e->next = G->adjList[5].first;
G->adjList[5].first = e;
// 添加边 G->B->F->H
e = (EdgeNode*)malloc(sizeof(EdgeNode));
e->adjvex = 7; // 邻接顶点序号为H
e->next = G->adjList[6].first;
G->adjList[6].first = e;
e = (EdgeNode*)malloc(sizeof(EdgeNode));
e->adjvex = 5; // 邻接顶点序号为F
e->next = G->adjList[6].first;
G->adjList[6].first = e;
e = (EdgeNode*)malloc(sizeof(EdgeNode));
e->adjvex = 1; // 邻接顶点序号为B
e->next = G->adjList[6].first;
G->adjList[6].first = e;
// 添加边 H->D->E->G
e = (EdgeNode*)malloc(sizeof(EdgeNode));
e->adjvex = 6; // 邻接顶点序号为G
e->next = G->adjList[7].first;
G->adjList[7].first = e;
e = (EdgeNode*)malloc(sizeof(EdgeNode));
e->adjvex = 4; // 邻接顶点序号为E
e->next = G->adjList[7].first;
G->adjList[7].first = e;
e = (EdgeNode*)malloc(sizeof(EdgeNode));
e->adjvex = 3; // 邻接顶点序号为D
e->next = G->adjList[7].first;
G->adjList[7].first = e;
// 打印邻接表(字母)
EdgeNode* p = NULL;
printf("边结点按邻接顶点字母打印:\n");
for (i = 0; i < G->numNodes; i++) {
printf("%c", G->adjList[i].data);
p = G->adjList[i].first;
while (p != NULL) {
printf("->%c", G->adjList[p->adjvex].data); // 打印邻接顶点字母
p = p->next;
}
printf("\n");
}
// 打印邻接表(下标)
printf("\n边结点按邻接下标打印:\n");
for (i = 0; i < G->numNodes; i++) {
printf("%c", G->adjList[i].data);
p = G->adjList[i].first;
while (p != NULL) {
printf("->%d", p->adjvex); // 打印邻接顶点下标
p = p->next;
}
printf("\n");
}
}
// 广度优先遍历
void BFSTraverse(GraphAdjList G) {
int i;
EdgeNode* p;
SeqQueue Q;
for (i = 0; i < G.numNodes; i++) {
visited[i] = FALSE; // 初始化所有顶点为未访问状态
}
InitQueue(&Q); // 初始化队列
printf("\n广度优先遍历的结果为(BFS):\n");
for (i = 0; i < G.numNodes; i++) {
if (!visited[i]) { // 对每个未访问的顶点进行操作
visited[i] = TRUE; // 标记为已访问
printf("%c", G.adjList[i].data); // 打印顶点数据
Enqueue(&Q, i); // 入队操作
while (!QueueIsEmpty(Q)) // 当队列不为空时
{
Dequeue(&Q, &i); // 出队操作
p = G.adjList[i].first; // 获取当前顶点的第一条边
while (p) {
if (!visited[p->adjvex]) // 如果边的终点未访问
{
visited[p->adjvex] = TRUE; // 标记为已访问
printf("->%c", G.adjList[p->adjvex].data); // 打印边的终点数据
Enqueue(&Q, p->adjvex); // 入队操作
}
p = p->next; // 移动到下一条边
}
}
}
}
printf("\n");
}
int main() {
GraphAdjList G;
G.numNodes = MAXVEX; // 设置顶点数
CreateALGraph(&G);
BFSTraverse(G); // 进行广度优先遍历
return 0;
}
运行结果: