數據結構與算法————圖的遍歷DFS深度優先搜索和BFS廣度優先搜索

圖的遍歷

圖的遍歷是指從圖中的任一頂點出發,對圖中的所有頂點訪問一次且只訪問一次的次序序列。例如迷宮探索就是把迷宮中的所有路都走一遍。遍歷可以解決很多問題,最常見的就是求最短路徑。主要有兩種搜索算法,深搜和廣搜。

深度優先搜索DFS

DFS是對先序遍歷的推廣。從某個頂點v開始處理v,然後遞歸的遍歷所有與v相鄰的頂點。
用圖說話,以無向無權圖爲例。
在這裏插入圖片描述
假如我們現在要從0號頂點開始,遍歷上圖中全部其他頂點。 首先訪問0號頂點,判斷與0相鄰的頂點2、7、5是否可以訪問,剛開始肯定沒有。先訪問2,再判斷與2相鄰的頂點是否可以訪問,如此反覆,經過6、4到7時,發現與7相鄰的0和4都已訪問過,訪問1,1,沒有別的點可以訪問了,返回到7。與7相鄰的都訪問完了,返回到4,訪問與4相鄰的其他頂點。到3,再到5。5沒有可訪問的,返回到4,4也沒有可訪問的了,返回到6->2->0。這時返回到了起點,說明遍歷完成。

回顧上面的遍歷過程,我們發現要完成遍歷,必須得有保存每個頂點之間的關係,可以鄰接矩陣或者鄰接表存儲。同時還需要標記每個頂點的訪問狀態。有必要還需要記錄走過的路徑。

DFS的僞代碼如下:
在這裏插入圖片描述
鄰接表實現的代碼如下:

/* 鄰接表存儲的圖 - DFS */
 
void Visit( Vertex V )
{
    printf("正在訪問頂點%d\n", V);
}
 
/* Visited[]爲全局變量,已經初始化爲false */
void DFS( LGraph Graph, Vertex V, void (*Visit)(Vertex) )
{   /* 以V爲出發點對鄰接表存儲的圖Graph進行DFS搜索 */
    PtrToAdjVNode W;
     
    Visit( V ); /* 訪問第V個頂點 */
    Visited[V] = true; /* 標記V已訪問 */
 
    for( W=Graph->G[V].FirstEdge; W; W=W->Next ) /* 對V的每個鄰接點W->AdjV */
        if ( !Visited[W->AdjV] )    /* 若W->AdjV未被訪問 */
            DFS( Graph, W->AdjV, Visit );    /* 則遞歸訪問之 */
}

BFS

廣搜類似於層序遍歷,需要用到隊列來完成。
假設從圖中的某個頂點v出發,在訪問v之後依次訪問v0的各個未曾訪問過的鄰接點,然後分別從這些鄰接點出發依次訪向它們的鄰接點,並使“先被訪問的頂點的鄰接點"先於“後被訪問的頂點的鄰接點”被訪問,直至圖中所有已被訪問的頂點的鄰接點都被訪問到。若此時圖中尚有頂點未被訪問,則另選圖中-個未曾被訪問的頂點作起始點,重複上述過程,直至圖中所有頂點都被訪問到爲止。換句話說,廣度優先搜索遍歷圖的過程中以0。爲起始點,由近至遠,依次訪問和。有路徑相通且路徑長度爲,2…的頂點。
在這裏插入圖片描述

代碼:

/* 鄰接矩陣存儲的圖 - BFS */
 
/* IsEdge(Graph, V, W)檢查<V, W>是否圖Graph中的一條邊,即W是否V的鄰接點。  */
/* 此函數根據圖的不同類型要做不同的實現,關鍵取決於對不存在的邊的表示方法。*/
/* 例如對有權圖, 如果不存在的邊被初始化爲INFINITY, 則函數實現如下:         */
bool IsEdge( MGraph Graph, Vertex V, Vertex W )
{
    return Graph->G[V][W]<INFINITY ? true : false;
}
 
/* Visited[]爲全局變量,已經初始化爲false */
void BFS ( MGraph Graph, Vertex S, void (*Visit)(Vertex) )
{   /* 以S爲出發點對鄰接矩陣存儲的圖Graph進行BFS搜索 */
    Queue Q;     
    Vertex V, W;
 
    Q = CreateQueue( MaxSize ); /* 創建空隊列, MaxSize爲外部定義的常數 */
    /* 訪問頂點S:此處可根據具體訪問需要改寫 */
    Visit( S );
    Visited[S] = true; /* 標記S已訪問 */
    AddQ(Q, S); /* S入隊列 */
     
    while ( !IsEmpty(Q) ) {
        V = DeleteQ(Q);  /* 彈出V */
        for( W=0; W<Graph->Nv; W++ ) /* 對圖中的每個頂點W */
            /* 若W是V的鄰接點並且未訪問過 */
            if ( !Visited[W] && IsEdge(Graph, V, W) ) {
                /* 訪問頂點W */
                Visit( W );
                Visited[W] = true; /* 標記W已訪問 */
                AddQ(Q, W); /* W入隊列 */
            }
    } /* while結束*/
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章