/**
* 無向圖
*
* 廣度優先搜索:初始化每個點的標記爲未檢查,選一個起始點入隊列,貼上待檢查標記,
* 然後該點出隊列,尋找所有標記爲未檢查的相鄰點並將其入棧(同時修改其標記爲待檢查),
* 對於已經出隊列的點,標記爲已檢查。終止條件:隊列爲空
*
* 深度優先:採用迭代的方式,類似於樹的遍歷,但是要在遍歷過程中檢查當前點是否已經並遍歷過
*/
function Graph(){
this.vertices = [];//圖的頂點
this.edgeList = new Map();//採用鄰接表保存邊,使用的是JavaScript的Map數據結構
}
Graph.prototype = {
//添加頂點
addVertex: function(value){
this.edgeList.set(value, []);
return this.vertices.push(value);
},
//添加邊,兩個方向都添加
addEdge: function(value1, value2){
if(!this.edgeList.get(value1))return false;
if(!this.edgeList.get(value2))return false;
this.edgeList.get(value1).push(value2);
this.edgeList.get(value2).push(value1);
return true;
},
//打印鄰接表到控制檯
print: function(){
var str = "";
for(let i = this.vertices.length-1;i>=0;i--){
str += this.vertices[i]+" : ";
str += this.edgeList.get(this.vertices[i]).join(",");
str += "\n";
}
console.log(str);
return str;
},
//廣度優先搜索
bfs: function(callback,start){
//distances、predecessors用於統計最短距離
var distances = [];//距離
var predecessors = [];//前溯點
start = start || this.vertices[0];
var queue = [];
queue.push(start);//注意,push會改變原數組,但是其返回值是新數組的長度
var edgeList = this.edgeList;
var isTrav = new Map();
this.vertices.forEach(function(v){
isTrav.set(v,0);
distances[v] = 0;
predecessors[v] = null;
});
isTrav.set(start, 1);
while(queue.length>0){
var u = queue.shift();
var neighbors = edgeList.get(u);
for(let i=0;i<neighbors.length;i++){
var w = neighbors[i];
if(isTrav.get(w) === 0){
isTrav.set(w, 1);
queue.push(w);
distances[w] = distances[u] + 1;
predecessors[w] = u;
}
}
isTrav.set(u, 2);
callback(u);
}
return {
distances:distances,
predecessors:predecessors
};
},
//深度優先搜索
dfs: function(callback, start){
start = start || this.vertices[0];
var isTrav = new Map();
this.vertices.forEach(function(v){
isTrav.set(v,0);
});
this.dfsVisit(start, isTrav, callback);
},
dfsVisit: function(n, isTrav, callback){
isTrav.set(n, 1);
callback(n);
var neighbors = this.edgeList.get(n);
for(let i=0;i<neighbors.length;i++){
var w = neighbors[i];
if(isTrav.get(w) == 0){
this.dfsVisit(w, isTrav, callback);
}
}
isTrav.set(n, 2);
}
};
var graph = new Graph();
var myVertices = ['A','B','C','D','E','F'];
myVertices.forEach(function(v){
graph.addVertex(v);
});
graph.addEdge('A','B');
graph.addEdge('A','C');
graph.addEdge('A','D');
graph.addEdge('C','D');
graph.addEdge('C','E');
graph.addEdge('D','E');
graph.addEdge('D','H');
graph.addEdge('B','E');
graph.addEdge('B','F');
console.log("鄰接表:");
graph.print();
console.log("廣度優先:");
var d = graph.bfs(function(v){console.log(v);});
console.log(d);
console.log("深度優先:");
graph.dfs(function(v){console.log(v);});
輸出:
鄰接表:
F : B
E : C,D,B
D : A,C,E
C : A,D,E
B : A,E,F
A : B,C,D
廣度優先:
A
B
C
D
E
F
{ distances: [ A: 0, B: 1, C: 1, D: 1, E: 2, F: 2 ],
predecessors: [ A: null, B: 'A', C: 'A', D: 'A', E: 'B', F: 'B' ] }
深度優先:
A
B
E
C
D
F