深度讲解邻接表图结构与广度优先搜索(BFS)

 广度优先搜索(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的路径
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值