/**
* 无向图
*
* 广度优先搜索:初始化每个点的标记为未检查,选一个起始点入队列,贴上待检查标记,
* 然后该点出队列,寻找所有标记为未检查的相邻点并将其入栈(同时修改其标记为待检查),
* 对于已经出队列的点,标记为已检查。终止条件:队列为空
*
* 深度优先:采用迭代的方式,类似于树的遍历,但是要在遍历过程中检查当前点是否已经并遍历过
*/
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