一、实现邻接表
代码实现:
var Graph = function() {
var vertices = []; // 初始化顶点
var adjList = {}; // 初始化边
// 添加顶点
this.addVertices = function(v){
vertices.push(v); // 添加顶点
adjList[v] = []; // 初始化顶点对应的边
}
// 添加边
this.addEdge = function(v1, v2) {
adjList[v1].push(v2);
adjList[v2].push(v1);
}
// 打印
this.print = function() {
console.log(adjList)
var s = '\n';
for(var i = 0; i < vertices.length; i++ ){
var v = vertices[i];
s += v + '=>';
for(var j = 0; j < adjList[v].length; j++ ){
s += adjList[v][j];
}
s += '\n'
}
console.log(s)
}
}
var graph = new Graph();
graph.addVertices('A')
graph.addVertices('B')
graph.addVertices('C')
graph.addVertices('D')
graph.addVertices('E')
graph.addVertices('F')
graph.addEdge('A','B')
graph.addEdge('A','C')
graph.addEdge('A','D')
graph.addEdge('C','D')
graph.addEdge('B','E')
graph.addEdge('B','F')
graph.print()
打印结果:
二、图遍历
1.广度遍历(BFS:Breadth-First Search)
(1)基本实现
代码实现:
1.将所有顶点的颜色设为白色;
2.创建一个队列;
3.首个顶点入队列;
4.循环队列是否为空, 若不为空,将第一个元素出栈,遍历其adjList,如果其中的顶点颜色为白色,则改为灰色并入队列;遍历完adjList后颜色设为黑色,并执行回调函数。
// 实现广度遍历
// 具体实现:
// 1.将所有顶点的颜色设为白色;
// 2.创建一个队列;
// 3.首个顶点入队列;
// 4.循环队列是否为空,
// 若不为空,将第一个元素出栈,遍历其adjList,如果其中的顶点颜色为白色,则改为灰色并入队列;遍历完adjList后颜色设为黑色,并执行回调函数
var initColor = function() {
var color = {};
for(var i = 0; i < vertices.length; i++) {
color[vertices[i]] = 'white';
}
return color;
}
this.bfs = function(v,callback) {
// 所有顶点的颜色设为白色
var color = initColor();
// 创建队列
var queue = new Queue();
// 将第一个顶点放入队列中
queue.enqueue(v);
while(!queue.isEmpty()) {
// 将队列头出栈
var now = queue.dequeue()
// 循环其边
for(var i = 0; i < adjList[now].length; i++) {
// 查看顶点颜色是否为白色,若是,则改为灰色,并入队
var edge = adjList[now]
var vi = adjList[now][i];
if(color[vi] == 'white') {
color[vi] = 'grey';
queue.enqueue(vi);
}
}
color[now] = 'black';
if(callback) {
callback(now);
}
}
}
(2)广度优先遍历和最短路径问题
代码实现:
// 广度优先遍历:设置了距离和回溯点 ,方便查找顶点到顶点之间的最短距离
this.BFS1 = function(v, callback) {
var color = initColor();
var queue = new Queue();
// 创建
var d = {}; // 距离
var pred = {}; // 回溯点
for(var i = 0; i < vertices.length; i++) {
d[vertices[i]] = 0;
pred[vertices[i]] = null;
}
queue.enqueue(v);
while(!queue.isEmpty()) {
var now = queue.dequeue();
for(var i = 0; i < adjList[now].length; i++) {
var vi = adjList[now][i]
if(color[vi] == 'white') {
color[vi] = 'grey';
// 添加距离和回溯点
d[vi] = d[now] + 1;
pred[vi] = now;
// 入列
queue.enqueue(vi);
}
}
color[now] = 'black';
if(callback) {
callback(now);
}
}
return{
pred:pred,
d:d
}
}
使用:
// 栈
var Stack = function() {
var items = [];
this.push = function(val) {
items.push(val);
}
this.pop = function() {
return items.pop();
}
this.isEmpty = function() {
return items.length == 0;
}
}
var graph = new Graph();
graph.addVertices('A')
graph.addVertices('B')
graph.addVertices('C')
graph.addVertices('D')
graph.addVertices('E')
graph.addVertices('F')
graph.addEdge('A','B')
graph.addEdge('A','C')
graph.addEdge('A','D')
graph.addEdge('C','D')
graph.addEdge('B','E')
graph.addEdge('B','F')
graph.print()
var log = function(v) {
console.log(v);
}
var s = graph.BFS1('A',log)
console.log(s);
// 最短路径:广度优先算法
var zuiduan = function(from, to) {
var v = to;
var path = new Stack();
while(v != from) {
path.push(v);
v = s.pred[v];
}
path.push(v);
var str = '';
while(!path.isEmpty()) {
str += path.pop() + '->';
}
str = str.slice(0,str.length - 2);
console.log(str)
}
zuiduan('A','F') // A->B->F
2.深度遍历(DFS:Depth-First Search)
思路:A中发现有白色顶点,则查看白色顶点中是否还含有白色顶点;A->B->E和F
代码实现:
// 深度遍历:像遍历树一样 递归
var dfsVisite = function(v, color, callback) {
color[v] = 'grey';
for(var i = 0; i<adjList[v].length;i++) {
var vi = adjList[v][i];
while(color[vi] == 'white') {
dfsVisite(vi,color,callback);
}
}
color[v] = 'black';
if(callback) {
callback(v);
}
}
this.DFS = function(v, callback) {
var color = initColor();
dfsVisite(v,color,callback);
}
打印结果: