广度优先搜索(BFS)
-
初始化一个访问数组
arr
,标记每个顶点是否被访问过。 -
使用队列来存储待处理的顶点,从起始顶点开始进行广度优先搜索。每次访问队列中的顶点,打印出该顶点的值,并将未访问过的邻接顶点加入队列。
#include <stdio.h>
#include <stdlib.h>
#define MaxVertex 7 // 图中最大顶点数
typedef char E; // 顶点类型为字符
// 头节点定义,保存一个元素和指向下一个节点的指针
struct HeadNode {
E element; // 存储元素
struct Node* next; // 指向下一个节点的指针
};
typedef struct Node { // 节点结构定义
int nextVertex; // 存储与当前顶点相邻接的顶点编号
struct Node* next; // 指向下一个节点的指针
} *Node;
// 邻接图定义
typedef struct AdjacencyGraph {
int vertexCount; // 顶点数量
int edgeCount; // 边的数量
struct HeadNode vertex[MaxVertex]; // 存储每个顶点的头节点
} *Graph;
// 创建图并初始化
Graph create() {
Graph graph = malloc(sizeof(struct AdjacencyGraph));
graph->vertexCount = graph->edgeCount = 0;
return graph;
}
// 向图中添加一个顶点
void addVertex(Graph graph, E e) {
graph->vertex[graph->vertexCount].element = e; // 将顶点e赋值给当前顶点
graph->vertex[graph->vertexCount].next = NULL; // 初始时该顶点没有邻接点
graph->vertexCount++; // 顶点数量加1
}
// 向图中添加一条边
void addEdge(Graph graph, int a, int b) {
Node node = graph->vertex[a].next; // 获取a顶点的第一个邻接节点
Node newnode = malloc(sizeof(struct Node)); // 创建新的节点
newnode->next = NULL; // 新节点指针初始化为空
newnode->nextVertex = b; // 设置新节点的邻接顶点为b
if (!node) { // 如果a顶点没有邻接节点,直接将新节点连接到a
graph->vertex[a].next = newnode;
} else { // 如果a顶点已经有邻接节点,遍历至最后插入新节点
do {
if (node->nextVertex == b) return; // 如果已经连接了顶点b,跳过
if (node->next) node = node->next; // 否则继续遍历
else break;
} while (1);
node->next = newnode; // 将新节点插入到节点链表末尾
}
graph->edgeCount++; // 边数加1
}
// 打印图的邻接表
void printGraph(Graph graph) {
for (int i = 0; i < graph->vertexCount; i++) {
printf("%d | %c", i, graph->vertex[i].element); // 打印顶点的编号和元素
Node node = graph->vertex[i].next; // 获取顶点i的邻接节点
while (node) {
printf(" -> %d", node->nextVertex); // 打印与当前顶点相邻的顶点
node = node->next; // 移动到下一个邻接节点
}
printf("\n");
}
}
// 队列节点定义
typedef int T;
struct QueueNode {
T element; // 存储元素
struct QueueNode* next; // 指向下一个节点的指针
};
typedef struct QueueNode* QNode;
struct Queue {
QNode front, rear; // 队列的前后指针
};
typedef struct Queue* LinkedQueue;
// 初始化队列
_Bool init(LinkedQueue queue) {
QNode node = malloc(sizeof(struct QueueNode)); // 创建一个新的队列节点
if (node == NULL) return 0; // 如果内存分配失败,返回0
queue->front = queue->rear = node; // 将队列的前后指针都指向该节点
return 1; // 初始化成功
}
// 向队列中添加一个元素
_Bool offer(LinkedQueue queue, T element) {
QNode node = malloc(sizeof(struct QueueNode)); // 创建新的队列节点
if (node == NULL) return 0; // 内存分配失败返回0
node->element = element; // 设置节点的元素
queue->rear->next = node; // 将新节点添加到队列末尾
queue->rear = node; // 更新队列的尾指针
return 1;
}
// 检查队列是否为空
_Bool isEmpty(LinkedQueue queue) {
return queue->rear == queue->front;
}
// 从队列中移除并返回队首元素
T pollQueue(LinkedQueue queue) {
T element = queue->front->next->element; // 获取队首元素
QNode node = queue->front->next; // 获取队首节点
queue->front->next = queue->front->next->next; // 更新队首指针
if (queue->rear == node) queue->rear = queue->front; // 如果队列只剩一个节点,更新尾指针
free(node); // 释放队首节点
return element; // 返回队首元素
}
// 广度优先搜索
void bfs(Graph graph, int startVertex, int targetVertex, int* visited, LinkedQueue queue) {
offer(queue, startVertex); // 将起始顶点加入队列
visited[startVertex] = 1; // 标记起始顶点为已访问
while (!isEmpty(queue)) { // 队列不为空,继续搜索
int next = pollQueue(queue); // 获取队首元素
printf("%c -> ", graph->vertex[next].element); // 打印当前节点
Node node = graph->vertex[next].next; // 获取当前节点的邻接节点
while (node) {
if (!visited[node->nextVertex]) { // 如果邻接节点未被访问
offer(queue, node->nextVertex); // 将邻接节点加入队列
visited[node->nextVertex] = 1; // 标记邻接节点为已访问
}
node = node->next; // 移动到下一个邻接节点
}
}
}
int main() {
Graph graph = create(); // 创建图
for (int c = 'A'; c <= 'G'; ++c) // 添加顶点
addVertex(graph, (char)c);
addEdge(graph, 0, 1); // A -> B
addEdge(graph, 1, 2); // B -> C
addEdge(graph, 1, 3); // B -> D
addEdge(graph, 1, 4); // B -> E
addEdge(graph, 4, 5); // E -> F
addEdge(graph, 3, 6); // D -> G
// 初始化访问数组,标记访问过的节点
int arr[graph->vertexCount];
for (int i = 0; i < graph->vertexCount; i++)
arr[i] = 0;
// 创建队列并进行广度优先搜索
struct Queue queue;
init(&queue);
bfs(graph, 0, 5, arr, &queue); // 从顶点A开始,查找到顶点F的路径
}