數據結構--圖

部分轉載自http://blog.csdn.net/hguisu/article/details/7712813


圖的表示

1、鄰接表

鄰接表的核心思想就是針對每個頂點設置一個鄰居表。

2、鄰接矩陣

鄰接矩陣的核心思想是針對每個頂點設置一個表,這個表包含所有頂點,通過True/False來表示是否是鄰居頂點。

概述

圖的遍歷是指從圖中的任一頂點出發,對圖中的所有頂點訪問一次且只訪問一次。圖的遍歷操作和樹的遍歷操作功能相似。圖的遍歷是圖的一種基本操作,圖的其它算法如求解圖的連通性問題,拓撲排序,求關鍵路徑等都是建立在遍歷算法的基礎之上。

由於圖結構本身的複雜性,所以圖的遍歷操作也較複雜,主要表現在以下四個方面:
① 在圖結構中,沒有一個“自然”的首結點,圖中任意一個頂點都可作爲第一個被訪問的結點。
② 在非連通圖中,從一個頂點出發,只能夠訪問它所在的連通分量上的所有頂點,因此,還需考慮如何選取下一個出發點以訪問圖中其餘的連通分量。
③ 在圖結構中,如果有迴路存在,那麼一個頂點被訪問之後,有可能沿迴路又回到該頂點。

④ 在圖結構中,一個頂點可以和其它多個頂點相連,當這樣的頂點訪問過後,存在如何選取下一個要訪問的頂點的問題。

圖的遍歷通常有深度優先搜索和廣度優先搜索兩種方式,他們對無向圖和有向圖都適用。

1.深度優先搜索

深度優先搜索(Depth_Fisrst Search)遍歷類似於樹的先根遍歷,是樹的先根遍歷的推廣。

 假設初始狀態是圖中所有頂點未曾被訪問,則深度優先搜索可從圖中某個頂點發v 出發,訪問此頂點,然後依次從v 的未被訪問的鄰接點出發深度優先遍歷圖,直至圖中所有和v 有路徑相通的頂點都被訪問到;若此時圖中尚有頂點未被訪問,則另選圖中一個未曾被訪問的頂點作起始點,重複上述過程,直至圖中所有頂點都被訪問到爲止。

以如下圖的無向圖G5爲例,進行圖的深度優先搜索:


G5

搜索過程:



假設從頂點v1 出發進行搜索,在訪問了頂點v1 之後,選擇鄰接點v2。因爲v2 未曾訪問,則從v2 出發進行搜索。依次類推,接着從v4 、v8 、v5 出發進行搜索。在訪問了v5 之後,由於v5 的鄰接點都已被訪問,則搜索回到v8。由於同樣的理由,搜索繼續回到v4,v2 直至v1,此時由於v1 的另一個鄰接點未被訪問,則搜索又從v1 到v3,再繼續進行下去由此,得到的頂點訪問序列爲:



顯然,這是一個遞歸的過程。爲了在遍歷過程中便於區分頂點是否已被訪問,需附設訪問標誌數組visited[0:n-1], ,其初值爲FALSE ,一旦某個頂點被訪問,則其相應的分量置爲TRUE。


2.廣度優先搜索

廣度優先搜索(Breadth_First Search) 遍歷類似於樹的按層次遍歷的過程。

假設從圖中某頂點v 出發,在訪問了v 之後依次訪問v 的各個未曾訪問過和鄰接點,然後分別從這些鄰接點出發依次訪問它們的鄰接點,並使“先被訪問的頂點的鄰接點”先於“後被訪問的頂點的鄰接點”被訪問,直至圖中所有已被訪問的頂點的鄰接點都被訪問到。若此時圖中尚有頂點未被訪問,則另選圖中一個未曾被訪問的頂點作起始點,重複上述過程,直至圖中所有頂點都被訪問到爲止。換句話說,廣度優先搜索遍歷圖的過程中以v 爲起始點,由近至遠,依次訪問和v 有路徑相通且路徑長度爲1,2,…的頂點。

對圖如下圖所示無向圖G5 進行廣度優先搜索遍歷:



廣度搜索過程:


首先訪問v1 和v1 的鄰接點v2 和v3,然後依次訪問v2 的鄰接點v4 和v5 及v3 的鄰接點v6 和v7,最後訪問v4 的鄰接點v8。由於這些頂點的鄰接點均已被訪問,並且圖中所有頂點都被訪問,由些完成了圖的遍歷。得到的頂點訪問序列爲:


v1→v2 →v3 →v4→ v5→ v6→ v7 →v8

和深度優先搜索類似,在遍歷的過程中也需要一個訪問標誌數組。並且,爲了順次訪問路徑長度爲2、3、…的頂點,需附設隊列以存儲已被訪問的路徑長度爲1、2、… 的頂點。



最小生成樹算法

1.Kruskal算法

此算法可以稱爲“加邊法”,初始最小生成樹邊數爲0,每迭代一次就選擇一條滿足條件的最小代價邊,加入到最小生成樹的邊集合裏。
1. 把圖中的所有邊按代價從小到大排序;
2. 把圖中的n個頂點看成獨立的n棵樹組成的森林;
3. 按權值從小到大選擇邊,所選的邊連接的兩個頂點ui,vi,應屬於兩顆不同的樹,則成爲最小生成樹的一條邊,並將這兩顆樹合併作爲一顆樹。
4. 重複(3),直到所有頂點都在一顆樹內或者有n-1條邊爲止。

2.Prim算法

此算法可以稱爲“加點法”,每次迭代選擇代價最小的邊對應的點,加入到最小生成樹中。算法從某一個頂點s開始,逐漸長大覆蓋整個連通網的所有頂點。

  1. 圖的所有頂點集合爲V;初始令集合u={s},v=Vu;
  2. 在兩個集合u,v能夠組成的邊中,選擇一條代價最小的邊(u0,v0),加入到最小生成樹中,並把v0併入到集合u中。
  3. 重複上述步驟,直到最小生成樹有n-1條邊或者n個頂點爲止。

由於不斷向集合u中加點,所以最小代價邊必須同步更新;需要建立一個輔助數組closedge,用來維護集合v中每個頂點與集合u中最小代價邊信息。


最短路徑算法

Dijkstra算法介紹

  • 算法特點:

    迪科斯徹算法使用了廣度優先搜索解決賦權有向圖或者無向圖的單源最短路徑問題,算法最終得到一個最短路徑樹。該算法常用於路由算法或者作爲其他圖算法的一個子模塊。

  • 算法的思路

    Dijkstra算法採用的是一種貪心的策略,聲明一個數組dis來保存源點到各個頂點的最短距離和一個保存已經找到了最短路徑的頂點的集合:T,初始時,原點 s 的路徑權重被賦爲 0 (dis[s] = 0)。若對於頂點 s 存在能直接到達的邊(s,m),則把dis[m]設爲w(s, m),同時把所有其他(s不能直接到達的)頂點的路徑長度設爲無窮大。初始時,集合T只有頂點s。
    然後,從dis數組選擇最小值,則該值就是源點s到該值對應的頂點的最短路徑,並且把該點加入到T中,OK,此時完成一個頂點,
    然後,我們需要看看新加入的頂點是否可以到達其他頂點並且看看通過該頂點到達其他點的路徑長度是否比源點直接到達短,如果是,那麼就替換這些頂點在dis中的值。
    然後,又從dis中找出最小值,重複上述動作,直到T中包含了圖的所有頂點。

Floyd算法的介紹

  • 算法的特點:
    弗洛伊德算法是解決任意兩點間的最短路徑的一種算法,可以正確處理有向圖或有向圖或負權(但不可存在負權迴路)的最短路徑問題,同時也被用於計算有向圖的傳遞閉包。

  • 算法的思路

通過Floyd計算圖G=(V,E)中各個頂點的最短路徑時,需要引入兩個矩陣,矩陣S中的元素a[i][j]表示頂點i(第i個頂點)到頂點j(第j個頂點)的距離。矩陣P中的元素b[i][j],表示頂點i到頂點j經過了b[i][j]記錄的值所表示的頂點。

假設圖G中頂點個數爲N,則需要對矩陣D和矩陣P進行N次更新。初始時,矩陣D中頂點a[i][j]的距離爲頂點i到頂點j的權值;如果i和j不相鄰,則a[i][j]=∞,矩陣P的值爲頂點b[i][j]的j的值。 接下來開始,對矩陣D進行N次更新。第1次更新時,如果”a[i][j]的距離” > “a[i][0]+a[0][j]”(a[i][0]+a[0][j]表示”i與j之間經過第1個頂點的距離”),則更新a[i][j]爲”a[i][0]+a[0][j]”,更新b[i][j]=b[i][0]。 同理,第k次更新時,如果”a[i][j]的距離” > “a[i][k-1]+a[k-1][j]”,則更新a[i][j]爲”a[i][k-1]+a[k-1][j]”,b[i][j]=b[i][k-1]。更新N次之後,操作完成!



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章