本文是博主深感算法方面的不足,做的一系列讀書筆記和源碼分析。
原文地址:學習javascript數據結構與算法(六)——圖,以爲有用的話能夠給個star,謝謝啦。
做者:wengjqjavascript
圖是網絡結構的抽象模型。圖是一組由邊鏈接的節點,任何二元關係均可以用圖來表示。前端
一個圖G = (V,E)由如下元素組成。java
下圖表示一個圖:git
由一條邊鏈接在一塊兒的頂點稱爲相鄰頂點。好比上圖的A和B是相鄰的,A和D是相鄰的,A和C是相鄰的,A和E不是相鄰的。一個頂點的度是其相鄰頂點的數量。好比,A和其餘三個頂點相鏈接,所以,A的度爲3;E和其餘兩個頂點相連,所以E的度爲2。路徑是頂點v1,v2,...,vk的一個連續序列,其中v[i]和v[i+1]是相鄰的。以上的圖爲例,其中的路徑有ABEI和ACDG。github
圖最多見的實現是鄰接矩陣。每一個節點都和一個整數相關聯,該整數做爲數組的索引。這裏不做討論。另外一種圖的表示方式是一種叫作鄰接表的動態數據結構。鄰接表由圖中每一個頂點的相鄰頂點列表所組成。咱們能夠用數組,鏈表,甚至是散列表或是字典來表示相鄰頂點列表。下面的示意圖展現了鄰接表的數據結構。咱們後面也會用代碼示例這種數據結構。算法
示例代碼以下:數組
function Graph() {
var vertices = []; //存儲圖中全部的頂點名字
var adjList = new Dictionary();//用以前的一個字典來存儲鄰接表
this.addVertex = function(v){ //添加頂點
vertices.push(v);
adjList.set(v, []); //頂點爲鍵,字典值爲空數組
};
this.addEdge = function(v, w){ //添加邊
adjList.get(v).push(w); //基於有向圖
adjList.get(w).push(v); //基於無向圖
};
this.toString = function(){
var s = '';
for (var i=0; i<vertices.length; i++){
s += vertices[i] + ' -> ';
var neighbors = adjList.get(vertices[i]);
for (var j=0; j<neighbors.length; j++){
s += neighbors[j] + ' ';
}
s += '\n';
}
return s;
};
var initializeColor = function(){
var color = [];
for (var i=0; i<vertices.length; i++){
color[vertices[i]] = 'white';
}
return color;
};
}
//測試
var graph = new Graph();
var myVertices = ['A','B','C','D','E','F','G','H','I'];
for (var i=0; i<myVertices.length; i++){
graph.addVertex(myVertices[i]);
}
graph.addEdge('A', 'B');
graph.addEdge('A', 'C');
graph.addEdge('A', 'D');
graph.addEdge('C', 'D');
graph.addEdge('C', 'G');
graph.addEdge('D', 'G');
graph.addEdge('D', 'H');
graph.addEdge('B', 'E');
graph.addEdge('B', 'F');
graph.addEdge('E', 'I');
console.log(graph.toString());
結果以下:
A -> B C D
B -> A E F
C -> A D G
D -> A C G H
E -> B I
F -> B
G -> C D
H -> D
I -> E 複製代碼
和樹的數據結構相似,咱們能夠訪問圖的全部節點。有兩種算法能夠對圖進行遍歷:廣度優先搜索(Breadth-First Search,BFS)和深度優先搜索(Depth-First Search,DFS)。圖遍歷能夠用來尋找特定的頂點或尋找兩個頂點之間的路徑,檢查圖是否連通,檢查圖是否含有環等。微信
圖遍歷算法的思想是必須追蹤每一個第一次訪問的節點,而且追蹤有哪些節點尚未被徹底探索。對於兩種圖遍歷算法,都須要明確指出第一個被訪問的頂點。徹底探索一個頂點要求咱們查看該頂點的每一條邊。對應每一條邊所鏈接的沒有被訪問過的頂點,將其標註爲被發現的,並將其加進待訪問頂點列表中。網絡
爲了保證算法的效率,務必訪問每一個頂點至多兩次。連通圖中每條邊和頂點都會被訪問到。當要標註已經訪問過的頂點時,咱們用三種顏色來反映它們的狀態:數據結構
廣度優先搜索算法會從指定的第一個頂點開始遍歷圖,先訪問其全部的相鄰點,就像一次訪問圖的一層。換句話說,就是先寬後深的訪問頂點。如下是從頂點v開始的廣度優先搜索算法所遵循的步驟。
(a)將u從Q中出隊列;
(b)將標註u爲被發現的(灰色);
(c)將u全部未被訪問過的鄰點(白色)入隊列;
(d)將u標註爲已被探索的(黑色);複製代碼
示例代碼以下:
var initializeColor = function(){
var color = [];
for (var i=0; i<vertices.length; i++){
color[vertices[i]] = 'white'; //初始化全部的頂點都是白色
}
return color;
};
this.bfs = function(v, callback){
var color = initializeColor(),
queue = new Queue(); //建立一個隊列
queue.enqueue(v); //入隊列
while (!queue.isEmpty()){
var u = queue.dequeue(), //出隊列
neighbors = adjList.get(u); //鄰接表
color[u] = 'grey'; //發現了但還未完成對其的搜素
for (var i=0; i<neighbors.length; i++){
var w = neighbors[i]; //頂點名
if (color[w] === 'white'){
color[w] = 'grey'; //發現了它
queue.enqueue(w); //入隊列循環
}
}
color[u] = 'black'; //已搜索過
if (callback) {
callback(u);
}
}
};
//測試以下:
function printNode(value){
console.log('Visited vertex: ' + value);
}
graph.bfs(myVertices[0], printNode);
結果以下:
Visited vertex: A
Visited vertex: B
Visited vertex: C
Visited vertex: D
Visited vertex: E
Visited vertex: F
Visited vertex: G
Visited vertex: H
Visited vertex: I複製代碼
深度優先搜索算法將會是從第一個指定的頂點開始遍歷圖,沿着路徑直到這條路徑最後一個頂點被訪問了,接着原路回退並探索下一條路徑。換句話說,它是先深度後廣度地訪問頂點。深度優先搜索算法不須要一個源頂點。要訪問頂點v,照以下的步驟作:
(a)訪問頂點w。複製代碼
如你所見,深度優先搜索的步驟是遞歸的,這意味着深度優先搜索算法使用棧來存儲函數調用(由遞歸調用所建立的棧)。示例代碼以下:
this.dfs = function(callback){
var color = initializeColor(); //前面的顏色數組
for (var i=0; i<vertices.length; i++){
if (color[vertices[i]] === 'white'){
dfsVisit(vertices[i], color, callback); //遞歸調用未被訪問過的頂點
}
}
};
var dfsVisit = function(u, color, callback){
color[u] = 'grey';
if (callback) {
callback(u);
}
var neighbors = adjList.get(u); //鄰接表
for (var i=0; i<neighbors.length; i++){
var w = neighbors[i];
if (color[w] === 'white'){
dfsVisit(w, color, callback); //添加頂點w入棧
}
}
color[u] = 'black';
};
//測試以下:
function printNode(value){
console.log('Visited vertex: ' + value);
}
graph.dfs(printNode);
結果以下:
Visited vertex: A
Visited vertex: B
Visited vertex: E
Visited vertex: I
Visited vertex: F
Visited vertex: C
Visited vertex: D
Visited vertex: G
Visited vertex: H複製代碼
本文對你有幫助?歡迎掃碼加入前端學習小組微信羣: