[Algorithm] Graph

圖的概念有點多,在此只討論最基礎的內容,因此選擇比較薄的高教版《數據結構》。html

1.4 非線性數據結構--圖 ........................................................................................................... 101
1.4.1 圖的基本概念.............................................................................................................. 102
1.4.2 圖形結構的物理存儲方式........................................................................................... 104
1.4.2.1 相鄰矩陣.......................................................................................................................... 104
1.4.2.2 圖的鄰接表示 .................................................................................................................. 105
1.4.2.3 圖的多重鄰接表示 .......................................................................................................... 107
1.4.3 圖形結構的遍歷.......................................................................................................... 108
1.4.4 無向連通圖的最小生成樹(minimum-cost spanning tree:MST).............................. 112
1.4.5 有向圖的最短路徑 ...................................................................................................... 114
1.4.5.1 單源最短路徑(single-source shortest paths) ..................................................... 115
1.4.5.2 每對頂點間最短路經(all-pairs shortest paths) ................................................. 117
1.4.6 拓撲排序 ..................................................................................................................... 119

涉及到的內容:數據結構之圖【還能夠的大綱】node

 

 

三種表達

From: https://www.cs.usfca.edu/~galles/visualization/DFS.html算法

    • Logical Representation
    • Adjacency List Representation
    • Adjacency Matrix Representation

 

「普通」鄰接表示

struct node{
  bool mark; //訪問標誌
  char letter; //頂點數據域
  struct edge *out; //指向邊表的指針
};
struct edge{   bool mark; //訪問標誌   int no; //頂點編號   struct edge *link; //指向邊表的後繼 };

 

多重鄰接表示

表節點存儲的不是頂點的序號,而是指向邊(或者說弧)另外一端相鄰頂點的指針。數組

struct node{
  bool mark; //訪問標誌
  char letter; //頂點數據域
  struct node *nextnode; //指向圖頂點集合中下一個元素的指針
  struct arc *out; //指向該頂點邊表的指針
};
struct arc{   bool mark; //訪問標誌   struct node *link; //指向該弧(邊)的另外一端頂點的指針   struct arc *nextarc; // 指向與該頂點鏈接的其他弧(邊)的指針 };

 

看上去特別像倒排表:[IR] Inverted Index & Boolean retrieval網絡

 

 

 

圖的遍歷 

一些概念

連通:若是從v到w存在一條(無向)路徑,則稱v和w是連通的數據結構

路徑:v到w的路徑是一系列的頂點的集合,其中任一對相鄰的頂點間都有圖中的邊。路徑的長度是路徑中的邊數(若是帶權,則是全部邊的權重和)。若是v和w之間的全部頂點都不一樣,則稱簡單路徑(無迴路)post

迴路:起點等於終點的路徑優化

連通圖:圖中任意兩頂點均連通url

連通份量:無向圖中的極大連通子圖spa

強連通;有向圖中頂點v和w之間存在雙向路徑(既有從v->w又有從w->v,能夠不是同一條),則稱v和w是強連通

弱連通:去掉方向後的v和w是連通的

強連通圖:有向圖中任意兩頂點均強連通

強連通份量:有向圖的極大強連通子圖

 

遍歷實現

不一樣的起點,會致使不一樣的遍歷路徑,也就生成了不一樣的「生成樹」。

    • 深度優先(depth-first search:DFS)
    • 寬度優先(breadth-first search:BFS)

Depth First Search, DFS

 

Breadth First Search, BFS

廣度優先搜索六層,就是「六度空間」 問題。

 

 

圖的優化問題

"無向連通圖" 的最小生成樹(minimum-cost spanning tree:MST

既然從不一樣的頂點出發會有不一樣的生成樹,而 n 個頂點的生成樹有 n-1 條邊,那麼,當邊帶權的時候(網絡),如何尋找一個(網絡中)的最小生成樹(即樹中各邊權值之和最小)?

如下內容具體參見:[Optimization] Greedy method

稠密圖的貪心算法:Prim算法

從一個點一點一點向外擴張延伸,進入樹內的點的dist都爲0,往外延伸時是與樹中任意一個結點距離最小

選擇整個樹周邊的「最小的邊」。

 

稀疏圖的貪心算法:Kruskal算法

每次從剩餘全部邊中取最短的邊,所選邊不能構成迴路

最小堆:查找最小的邊

並查集:要鏈接的倆點不在同一棵樹上。Goto: 超有愛的並查集

並查集的實現,int pre[1000]; 這個數組,記錄了每一個大俠的上級是誰。大俠們從1或者0開始編號(依據題意而定),pre[15]=3就表示15號大俠的上級是3號大俠。

若是一我的的上級就是他本身,那說明他就是掌門人了,查找到此爲止。也有孤家寡人自成一派的,好比歐陽鋒,那麼他的上級就是他本身。每一個人都只認本身的上級。好比胡青牛同窗只知道本身的上級是楊左使。

張無忌是誰?不認識!要想知道本身的掌門是誰,只能一級級查上去。 

路徑壓縮,每一個人經過指針在某一處查詢本身門派的頭兒。若是join有門派合併事件,則只修改門派的頭兒便可。

 

 

有向圖的最短路徑

單源最短路徑(single-source shortest paths)Dijkstra算法 (基於貪心算法)

Dijkstra算法和 最小生成樹Prim算法最小生成樹算法很是相似,你們能夠先熟悉下個算法。兩個算法都是基於貪心算法。

雖然Dijkstra算法相對來講比Bellman-Ford 算法更快,可是不適用於有負權值邊的圖,貪心算法決定了它的目光短淺。

而Bellman-Ford 算法從全局考慮,能夠檢測到有負權值的迴路。

 

Ref: Dijkstra算法(一)之 C語言詳解

核心思路

與S集合中相鄰的點中找到最小的(「邊」+相鄰點的「值」),而後更新倆集合便可。

若是edge存在負數,則會破壞以上這句話背後的原則。

時間複雜度:O(E+V*logV)

 

基本思想

指定起點s (即從頂點s開始計算)。

S:記錄已求出最短路徑的頂點 (以及相應的最短路徑長度);

U:記錄還未求出最短路徑的頂點 (以及該頂點到起點s的距離);

初始時,S中只有起點s;U中是除s以外的頂點,而且U中頂的路徑是"起點s到該頂點的路徑"。

而後,從U中找出路徑最短的頂點,並將其加入到S中;

接着,更新U中的頂點和頂點對應的路徑。

而後,再從U中找出路徑最短的頂點,並將其加入到S中;

接着,更新U中的頂點和頂點對應的路徑。 ... 重複該操做,直到遍歷完全部頂點。


操做步驟

(1) 初始時,S只包含起點s;U包含除s外的其餘頂點,且U中頂點的距離爲"起點s到該頂點的距離"[例如,U中頂點v的距離爲(s,v)的長度,而後s和v不相鄰,則v的距離爲∞]。

(2) 從U中選出"距離最短的頂點k",並將頂點k加入到S中;同時,從U中移除頂點k。

(3) 更新U中各個頂點到起點s的距離。之因此更新U中頂點的距離,是因爲上一步中肯定了k是求出最短路徑的頂點,從而能夠利用k來更新其它頂點的距離;例如,(s,v)的距離可能大於(s,k)+(k,v)的距離。

(4) 重複步驟(2)和(3),直到遍歷完全部頂點。

 

每對頂點間最短路經(all-pairs shortest paths)Floyed算法 (基於動態規劃)

Ref: Floyd 算法求多源最短路徑

Floyd算法用來找出每對頂點之間的最短距離,它對圖的要求是,

    • 既能夠是無向圖也能夠是有向圖,邊權能夠爲負。
    • 可是不能存在負環 (可根據最小環的正負來斷定)。

 

More details, please check : [Optimization] Dynamic programming

 

 

    /* 其餘內容,再補充 */

 

End.

相關文章
相關標籤/搜索