1. 程式人生 > 實用技巧 >無向圖深度優先遍歷(DFS)和廣度優先遍歷(BFS)演算法

無向圖深度優先遍歷(DFS)和廣度優先遍歷(BFS)演算法

定義

深度優先遍歷

(1)從圖中某個初始頂點v出發,首先訪問初始頂點v。
(2)選擇一個與頂點v相鄰且沒被訪問過的頂點w,再從w出發進行深度優先搜尋,直到圖中與當前頂點v鄰接的所有頂點都被訪問過為止。  
(3) 利用遞迴實現,簡單但是不好理解,時間複雜度 O(n+e)。

廣度優先遍歷

(1)訪問初始點v,接著訪問v的所有未被訪問過的鄰接點v1,v2,…,vt。
(2)按照v1,v2,…,vt的次序,訪問每一個頂點的所有未被訪問過的鄰接點。   
(3)依次類推,直到圖中所有和初始點v有路徑相通的頂點都被訪問過為止。
(4) 利用佇列實現, 時間複雜度 O(n+e).

實現程式碼

深度優先遍歷演算法

//深度優先遍歷演算法
void DFS(AdjGraph *G, int v)
{
    ArcNode *p;
    visited[v] = 1;
    printf("%d ", v);
    p = G->adjlist[v].firstarc;

    while(p != NULL) //p == NULL is the break of circle
    {
        if(visited[p->adjvex] == 0)
            DFS(G, p->adjvex);
        p=p->nextarc;
    } 
}

廣度優先遍歷演算法

//廣度優先遍歷演算法
void BFS(AdjGraph *G, int v)
{
    int w, i;
    ArcNode *p;
    SqQueue *qu;
    InitQueue(qu);
    int visited[MAXV];

    for(i = 0; i < G->n; i++)
        visited[i] = 0;
    
    printf("%2d",v);
    visited[v] = 1;

    enQueue(qu, v);

    while( !QueueEmpty(qu))
    {
        deQueue(qu, w);
        p = G->adjlist[w].firstarc;

        while(p!=NULL)
        {
            if(visited[p->adjvex] == 0)
            {
                printf("%2d", p->adjvex);
                visited[p->adjvex] = 1;
                enQueue(qu, p->adjvex);
            }
            p = p->nextarc;
        }
    }
    printf("\n");
}

注意理解

  1. 注意,DFS是基於遞迴形式的, 主要是往深入的方向去遍歷。 每次碰到可以讀取輸出的頂點就直接輸出,並且將其視作是頭節點陣列,接著向它的下一個進行讀取。
  2. BFS則比較憨厚,他是直接在一個頭節點陣列走到黑,一直到讀取NULL才肯回頭。這時候,需要利用佇列來儲存被它錯過的路口,給他提供後悔藥。回頭時隊列出棧,出一顆後悔藥給他吃,讓它接著往下一個方向一直走。一直等到它把後悔藥都吃完,然後就遍歷結束了。
全部程式碼
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <float.h>
#define ElemType int
#define maxsize 100
#define InfoType int
#define MAXV 100
#define MaxSize 100
#define INF 214748364 
#define INFINITE INF
/////////////////////////////////////////////////
//鄰接表的結構體定義
typedef struct ANode
{
    int adjvex;            //該邊的鄰接點的編號,即有向邊指向的頂點編號
    struct ANode *nextarc; //指向下一條邊的指標
    int weight;            //邊的相關的資訊,如權值
} ArcNode;                 //邊節點的型別

typedef struct Vnode
{
    InfoType info;     //頂點的其他資訊
    int count;         //存放頂點入度
    ArcNode *firstarc; //指向第一個邊節點
} VNode;               //鄰接表的頭節點的結構體型別

typedef struct
{
    VNode adjlist[MAXV]; //頭節點的陣列
    int n, e;            //圖的頂點數和邊數
} AdjGraph;              //整個鄰接表的資料結構體型別
//////////////////////////////////////////////////
//鄰接矩陣的結構體
typedef struct S
{
    int no;        //頂點的編號
    InfoType info; //頂點的其他資訊
} VertexType;      //頂點的型別

typedef struct SS
{
    int edges[MAXV][MAXV]; //鄰接矩陣的陣列
    int n, e;              //圖的頂點數和邊數
    VertexType vexs[MAXV]; //存放頂點資訊
} MatGraph;
///////////////////////////////////////////////////
typedef struct SSS
{
    ElemType data[maxsize];
    int front;
    int rear;
} SqQueue; //佇列的結構體
////////////////////////////////
//Kruskal演算法需要的簡化圖的結構體
typedef struct head
{
    int u; //邊的起始頂點
    int v; //邊的終止頂點
    int w; //邊的權值
} Edge;
///////////////////////////////
///零零零零啦啦啦啦啦
int visited[MAXV] = {0};
///////////////////////////////
//佇列的操作函式集合
//由於佇列的函式在另一個檔案
//所以需要宣告一下
void InitQueue(SqQueue *&q);
void DestoryQueue(SqQueue *&q);
bool QueueEmpty(SqQueue *q);
bool enQueue(SqQueue *&q, ElemType e);
bool deQueue(SqQueue *&q, ElemType &e);
/////////////////////////////////////////////////////////////////
//後序遍歷需要的一些佇列的基本函式
void InitQueue(SqQueue *&q)
{
    q = (SqQueue *)malloc(sizeof(SqQueue));
    q->front = q->rear = 0;
}

void DestoryQueue(SqQueue *&q)
{
    free(q);
}

bool QueueEmpty(SqQueue *q)
{
    return (q->front == q->rear);
}

bool enQueue(SqQueue *&q, ElemType e)
{
    if ((q->rear + 1) % maxsize == q->front)
        return false;
    q->rear = (q->rear + 1) % maxsize;
    q->data[q->rear] = e;
    return true;
}

bool deQueue(SqQueue *&q, ElemType &e)
{
    if (q->front == q->rear)
        return false;

    q->front = (q->front + 1) % maxsize;
    e = q->data[q->front];

    return true;
}
/////////////////////////////////////////////
void CreateAdj(AdjGraph *&G, int A[MAXV][MAXV], int n, int e)
{
    int i, j;
    ArcNode *p;
    G = (AdjGraph *)malloc(sizeof(AdjGraph));
    for (i = 0; i < n; i++)
        G->adjlist[i].firstarc = NULL;

    for (i = 0; i < n; i++)
        for (j = n - 1; j >= 0; j--)
            if (A[i][j] != 0 && A[i][j] != INF)
            {
                p = (ArcNode *)malloc(sizeof(ArcNode));
                p->adjvex = j;
                p->weight = A[i][j];
                p->nextarc = G->adjlist[i].firstarc;
                G->adjlist[i].firstarc = p;
            }
    G->n = n;
    G->e = e;
}

void DispAdj(AdjGraph *G) //輸出鄰接表G
{
    int i;
    ArcNode *p;
    for (i = 0; i < G->n; i++)
    {
        p = G->adjlist[i].firstarc;
        printf("%3d: ", i);
        while (p != NULL)
        {
            if (p->weight != 2147483647) //2147483647
                printf("%3d[%d]→", p->adjvex, p->weight);
            p = p->nextarc;
        }

        printf("^\n");
    }
}

void DestroyAdj(AdjGraph *&G) //銷燬鄰接表
{
    int i;
    ArcNode *pre, *p;
    for (i = 0; i < G->n; i++) //掃描所有的單鏈表
    {
        pre = G->adjlist[i].firstarc; //p指向第i個單鏈表的首結點
        if (pre != NULL)
        {
            p = pre->nextarc;
            while (p != NULL) //釋放第i個單鏈表的所有邊結點
            {
                free(pre);
                pre = p;
                p = p->nextarc;
            }
            free(pre);
        }
    }
    free(G); //釋放頭結點陣列
}

//////////////////////////////////////////////////////////
//無向圖鄰接表的深度優先演算法
void DFS(AdjGraph *G, int v)
{
    ArcNode *p;
    visited[v] = 1;
    printf("%d ", v);
    p = G->adjlist[v].firstarc;

    while(p != NULL) //p == NULL is the break of circle
    {
        if(visited[p->adjvex] == 0)
            DFS(G, p->adjvex);
        p=p->nextarc;
    } 
}
//////////////////////////////////////////////////////
void BFS(AdjGraph *G, int v)
{
    int w, i;
    ArcNode *p;
    SqQueue *qu;
    InitQueue(qu);
    int visited[MAXV];

    for(i = 0; i < G->n; i++)
        visited[i] = 0;
    
    printf("%2d",v);
    visited[v] = 1;

    enQueue(qu, v);

    while( !QueueEmpty(qu))
    {
        deQueue(qu, w);
        p = G->adjlist[w].firstarc;

        while(p!=NULL)
        {
            if(visited[p->adjvex] == 0)
            {
                printf("%2d", p->adjvex);
                visited[p->adjvex] = 1;
                enQueue(qu, p->adjvex);
            }
            p = p->nextarc;
        }
    }
    printf("\n");
}

int main ()
{
    int a[4][MAXV] = {{0, 1, 1, 1},
                   {1, 0, 1, 1},
                   {1, 1, 0, 0},
                   {1, 1, 0, 0}};
    AdjGraph* g;
    CreateAdj(g, a, 4, 5);

    printf("這是原始鄰接表的結構: \n");
    DispAdj(g);

    printf("\nthis is the Deep fist search (from '0'):\n");
    DFS(g, 0);

    printf("\nthis is the Broad fist search (from '0): \n");
    BFS(g, 0);

    system("pause");
    return 0;

}

原始資料

原始資料以及執行結果

記得點贊哦!