首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

無向圖廣度優先搜尋 (BFS) C 語言實作:鄰接表與循環佇列詳解

     編輯:關於C語言

一、BFS 核心思想:層層推進

BFS 從起始頂點出發,優先訪問距離為 1 的鄰接點,再訪問距離 2 的… 類似水波擴散。需輔助佇列儲存「已發現但未處理」的頂點。

二、循環佇列實作(高效能、定容量)

typedef struct {
    int *data;
    int front, rear;
    int capacity;
} Queue;

Queue *queue_create(int cap) {
    Queue *q = malloc(sizeof(Queue));
    q->data = malloc(cap * sizeof(int));
    q->front = q->rear = 0;
    q->capacity = cap;
    return q;
}

int queue_empty(Queue *q) { return q->front == q->rear; }
int queue_full(Queue *q) { return (q->rear + 1) % q->capacity == q->front; }

void queue_push(Queue *q, int v) {
    if (queue_full(q)) return; // 或擴容
    q->data[q->rear] = v;
    q->rear = (q->rear + 1) % q->capacity;
}

int queue_pop(Queue *q) {
    if (queue_empty(q)) return -1;
    int v = q->data[q->front];
    q->front = (q->front + 1) % q->capacity;
    return v;
}

void queue_destroy(Queue *q) { free(q->data); free(q); }

三、BFS 演算法與樹邊記錄

同樣使用三色標記,並記錄 parent[v] 重建最短路徑樹:

void BFS(Graph *G, int start, int *parent) {
    int *color = calloc(G->vexNum, sizeof(int));
    for (int i = 0; i < G->vexNum; i++) color[i] = WHITE;
    
    Queue *q = queue_create(G->vexNum + 1);
    color[start] = GRAY;
    parent[start] = -1; // 根節點無父節點
    queue_push(q, start);
    
    while (!queue_empty(q)) {
        int v = queue_pop(q);
        printf("%d ", v); // 處理頂點
        
        for (ArcNode *p = G->adjList[v].first; p; p = p->next) {
            if (color[p->adjvex] == WHITE) {
                color[p->adjvex] = GRAY;
                parent[p->adjvex] = v; // 記錄樹邊
                queue_push(q, p->adjvex);
            }
        }
        color[v] = BLACK;
    }
    printf("\n");
    free(color);
    queue_destroy(q);
}

四、完整可執行範例

#include <stdio.h>
#include <stdlib.h>

#define MAXV 100
#define WHITE -1
#define GRAY 0
#define BLACK 1

typedef struct ArcNode { int adjvex; struct ArcNode *next; } ArcNode;
typedef struct VNode { ArcNode *first; } VNode;

VNode adjList[MAXV];
int vexNum = 7;

void buildGraph() {
    int edges[][2] = {{0,1},{0,2},{1,3},{2,3},{2,4},{3,5},{4,5},{4,6},{5,6}};
    int m = sizeof(edges)/sizeof(edges[0]);
    for (int i = 0; i < m; i++) {
        int u = edges[i][0], v = edges[i][1];
        ArcNode *n1 = malloc(sizeof(ArcNode)); n1->adjvex = v; n1->next = adjList[u].first; adjList[u].first = n1;
        ArcNode *n2 = malloc(sizeof(ArcNode)); n2->adjvex = u; n2->next = adjList[v].first; adjList[v].first = n2;
    }
}

// 佇列實作同上...

void BFS(int start, int *parent) {
    int color[MAXV];
    for (int i = 0; i < vexNum; i++) color[i] = WHITE;
    int q[MAXV]; int front=0, rear=0;
    color[start] = GRAY; parent[start] = -1; q[rear++] = start;
    while (front != rear) {
        int v = q[front++];
        printf("%d ", v);
        for (ArcNode *p = adjList[v].first; p; p = p->next) {
            if (color[p->adjvex] == WHITE) {
                color[p->adjvex] = GRAY;
                parent[p->adjvex] = v;
                q[rear++] = p->adjvex;
            }
        }
        color[v] = BLACK;
    }
    printf("\n");
}

int main() {
    buildGraph();
    int parent[MAXV];
    printf("BFS (從 2 開始): ");
    BFS(2, parent);
    // 輸出: 2 0 1 3 5 4 6
    
    // 重建 2 到 6 的最短路徑
    printf("Path 2->6: ");
    int path[MAXV], len = 0;
    for (int v = 6; v != -1; v = parent[v]) path[len++] = v;
    for (int i = len-1; i >= 0; i--) printf("%d ", path[i]);
    printf("\n");
    return 0;
}

五、BFS 關鍵應用

  • 無權圖最短路徑:BFS 找到的路徑邊數最少。
  • 二分圖判定:嘗試二染色,相鄰頂點顏色衝突則非二分圖。
  • 拓撲排序 (Kahn 演算法):BFS 處理入度為 0 的頂點。
  • 連通分量:對未訪問頂點重複 BFS。
  • 網頁爬蟲:層層抓取連結。

六、DFS vs BFS 選型指南

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
場景推薦理由
最短路徑 (無權)BFS保證邊數最少
路徑存在性/連通性DFS記憶體較省,實作簡單
拓撲排序DFS (後序) / BFS (Kahn)皆可,DFS 更常用
迷宮生成/求解DFS自然回溯特性
二分圖判定BFS層次染色直觀
深度極大圖BFS (非遞迴)避免遞迴堆疊溢位