定義:圖由邊的集合及頂點的集合組成。頂點也有權重, 也稱爲成本。javascript
若是一個圖的頂點對是有序的, 則能夠稱之爲有向圖。在對有向圖中的頂點對排序後, 即可以在兩
個頂點之間繪製一個箭頭。 有向圖代表了頂點的流向。java
若是圖是無序的, 則稱之爲無序圖, 或無向圖。算法
圖中的一系列頂點構成路徑, 路徑中全部的頂點都由邊鏈接。 路徑的長度用路徑中第一個頂點到最後一個頂點之間邊的數量表示。 由指向自身的頂點組成的路徑稱爲環, 環的長度爲 0。數組
圈是至少有一條邊的路徑, 且路徑的第一個頂點和最後一個頂點相同。 不管是有向圖仍是無向圖, 只要是沒有重複邊或重複頂點的圈, 就是一個簡單圈。 除了第一個和最後一個頂點之外, 路徑的其餘頂點有重複的圈稱爲平凡圈。數據結構
若是兩個頂點之間有路徑, 那麼這兩個頂點就是強連通的, 反之亦然。 若是有向圖的全部的頂點都是強連通的, 那麼這個有向圖也是強連通的。函數
用Vertex類表示節點,Vertex 類有兩個數據成員: 一個用於標識頂點, 另外一個是代表這個頂點是否被訪問過的布爾值。它們分別被命名爲 label 和 wasVisited。this
function Vertex(label){ this.label = label; }
用鄰接表或鄰接表數組來表示邊。數組的索引表示頂點,元素是一個數組,裏面的成員是與該頂點相連的其餘頂點。所以鄰接表是一個二維的數組。prototype
搜索圖分兩種方式:深度優先和廣度優先。code
廣度優先搜索算法:數據結構是隊列。經過將頂點存入隊列中,最早入隊列的頂點先被探索。
深度優先搜索算法:數據結構是棧。經過將頂點存入棧中,沿着路徑探索頂點,存在新的相鄰頂點就去訪問。排序
深度優先
深度優先搜索包括從一條路徑的起始頂點開始追溯, 直到到達最後一個頂點, 而後回溯,繼續追溯下一條路徑, 直到到達最後的頂點, 如此往復, 直到沒有路徑爲止。
思路:訪問一個沒有訪問過的頂點, 將它標記爲已訪問, 再遞歸地去訪問在初始頂點的鄰接表中其餘沒有訪問過的頂點。
廣度優先
廣度優先搜索從第一個頂點開始, 嘗試訪問儘量靠近它的頂點。 本質上, 這種搜索在圖上是逐層移動的, 首先檢查最靠近第一個頂點的層, 再逐漸向下移動到離起始頂點最遠的層。
用JS實現以上兩種搜索方法:
// 建立圖類 function Graph(v){ this.vertices = v; // 共有多少個節點 this.edges = 0; // 有多少條邊 this.adj = []; // 鄰接表數組 for(var i = 0;i<this.vertices;i++){ this.adj[i] = []; } this.marked = []; // 用於搜索 for(var i = 0;i<this.vertices;i++){ this.marked[i] = false; } this.edgeTo = []; // 用於廣度優先搜索查找最短路徑 } Graph.prototype = { constructor: Graph, // 在兩個頂點間畫一條邊 addEdge(v, w){ this.adj[v].push(w); this.adj[w].push(v); this.edges++; }, showGraph(){ for(var i = 0;i<this.vertices;i++){ var str = ''; for(var j = 0;j<this.vertices;j++){ if(this.adj[i][j] !== undefined){ str += this.adj[i][j] + ' '; } } console.log(i + "-> " + str + '\n'); } }, // 深度優先搜索函數depth first searching,遞歸實現 dfs(v){ this.marked[v] = true; if(this.adj[v].length){ console.log("Visited vertex: " + v); for(var w of this.adj[v]){ if(!this.marked[w]){ this.dfs(w); } } } }, // 廣度優先搜索函數,無遞歸實現 bfs(s){ var queue = []; this.marked[s] = true; queue.push(s); while(queue.length > 0){ var v = queue.shift(); console.log("Visited vertex: " + v); for(var w of this.adj[v]){ if(!this.marked[w]){ this.edgeTo[w] = v; this.marked[w] = true; queue.push(w); } } } } }
利用廣度優先搜索方法查找最短路徑(查找頂點1和頂點4之間的最短路徑):
須要再擴展一個方法,經過執行一次廣度優先搜索後獲得的edgeTo數組來找到1和4節點之間相互鏈接的節點:
Graph.prototype.pathTo = function(w, v){ this.bfs(w); var source = w; // 頂點w做爲起點 if(!this.hasPathTo(v)){ return undefined; } var path = []; // 保存路徑,不過是從終點到起點的 for(var i = v; i != source; i = this.edgeTo[i]){ path.push(i); } path.push(source); return path; } Graph.prototype.hasPathTo(v){ return this.marked[v]; } var g = new Graph(6); g.addEdge(0, 1); g.addEdge(0, 2); g.addEdge(1, 5); g.addEdge(2, 3); g.addEdge(3, 5); g.addEdge(2, 4); g.showGraph(); g.pathTo(4, 1); // [1, 0, 2, 4]