* javascript Dictionary 类 通过HashTable 分离链接法
javascript Dictionary 类 通过HashTable 分离链接法_dictionary.prototype.has-CSDN博客
* javascript queue 队列类
javascript queue 队列类_js 队列工具类-CSDN博客
* 图的遍历
深度优先 + 广度优先
** 广度优先
当要标注已经访问过的顶点时,我们用三种颜色来反映它们的状态。
白色:表示该顶点还没有被访问。
灰色:表示该顶点被访问过,但并未被探索过。
黑色:表示该顶点被访问过且被完全探索过。
以下是从顶点v开始的广度优先搜索算法所遵循的步骤。
(1) 创建一个队列Q。
(2) 将v标注为被发现的(灰色),并将v入队列Q。
(3) 如果Q非空,则运行以下步骤:
(a) 将u从Q中出队列;
(b) 将标注u为被发现的(灰色);
(c) 将u所有未被访问过的邻点(白色)入队列; (d) 将u标注为已被探索的(黑色)。
** 深度优先
深度优先搜索算法不需要一个源顶点。在深度优先搜索算法中,若图中顶点v未访问,则访 问该顶点v。
要访问顶点v,照如下步骤做。
(1) 标注v为被发现的(灰色)。
(2) 对于v的所有未访问的邻点w:
(a) 访问顶点w。
(3) 标注v为已被探索的(黑色)。
深度优先搜索的步骤是递归的,这意味着深度优先搜索算法使用栈来存储函数调 用(由递归调用所创建的栈)。
* ./Collection/Stack.js
/**
* Created by Mch on 9/9/18.
*/
function Stack() {
this.items = [];
}
Stack.prototype = {
push: function(element) {
this.items.push(element);
},
pop: function() {
return this.items.pop();
},
peek: function() {
return this.items[this.items.length-1];
},
isEmpty: function () {
return this.items.length === 0;
},
size: function() {
return this.items.length;
},
clear: function() {
this.items = [];
},
print: function () {
console.log(this.items.toString());
}
};
exports.Stack = Stack;
* ./Collection/Graph.js
/**
* Created by Mch on 9/2/18.
*/
var Dictionary = require('./Dictionary').Dictionary,
Queue = require('./Queue').Queue,
Stack = require('./Stack').Stack,
Comparator = require('../utils/Comparator').Comparator;
function Graph() {
this.vertices = [];
// 邻接表由图中每个顶点的相邻顶 点列表所组成。
this.adjList = new Dictionary(new Comparator(function(/* String */a, /* String */b) {
return a.localeCompare(b);
}));
this.time = 0;
}
Graph.prototype = {
addVertex: function(v) {
this.vertices.push(v);
this.adjList.set(v, []);
},
addEdge: function(v, w) {
// 无向图
this.adjList.get(v).push(w);
this.adjList.get(w).push(v);
},
toString: function() {
var s = '', g = this;
this.vertices.forEach(function(v) {
s += v + ' -> ';
// neighbors
g.adjList.get(v).forEach(function(n) {
s += n + ' ';
});
s += '\n';
});
return s;
},
initializeColor: function() {
var color = [];
this.vertices.forEach(function(v) {
color[v] = 'white';
});
return color;
},
/**
* 广度优先搜索
* @param v
* @param callback
*/
bfs: function(v, callback) {
var color = this.initializeColor(),
queue = new Queue();
queue.enqueue(v);
while (!queue.isEmpty()) {
var u = queue.dequeue();
color[u] = 'grey';
/* neighbors */
this.adjList.get(u).forEach(function(w) {
if (color[w] === 'white') {
color[w] = 'grey';
queue.enqueue(w);
}
});
color[u]= 'black';
callback && callback(u);
}
},
/**
* 使用BFS寻找最短路径
* @param v
* @returns {{distances: Array, predecessors: Array}}
* 从v到u的距离d[u]
* 前溯点pred[u],用来推导出从v到其他每个顶点u的最短路径。
* @constructor
*/
BFS: function(v) {
var color = this.initializeColor(),
queue = new Queue(),
d = [], // 距离
pred = []; // 前溯点
queue.enqueue(v);
this.vertices.forEach(function(v) {
d[v] = 0;
pred[v] = null;
});
while (!queue.isEmpty()) {
var u = queue.dequeue();
color[u] = 'grey';
// neighbors
this.adjList.get(u).forEach(function(w) {
if (color[w] === 'white') {
color[w] = 'grey';
d[w] = d[u] + 1;
pred[w] = u;
queue.enqueue(w);
}
});
color[u] = 'black';
}
return {
distances: d,
predecessors: pred
}
},
dfs: function(callback) {
var color = this.initializeColor(), g = this;
this.vertices.forEach(function(v) {
if (color[v] === 'white') {
g.dfsVisit(v, color, callback);
}
});
},
dfsVisit: function(u, color, callback) {
color[u] = 'grey';
callback && callback(u);
var g = this;
// neighbors
this.adjList.get(u).forEach(function(w) {
if (color[w] === 'white') {
g.dfsVisit(w, color, callback);
}
});
color[u] = 'black';
},
DFS: function() {
var color = this.initializeColor(),
d = [],
f = [],
p = [],
g = this;
this.time = 0;
this.vertices.forEach(function(v) {
f[v] = 0;
d[v] = 0;
p[v] = null;
});
this.vertices.forEach(function(v) {
if (color[v] === 'white') {
g.DFSVisit(v, color, d, f, p);
}
});
return {
discovery: d,
finished: f,
processors: p
}
},
DFSVisit: function(u, color, d, f, p) {
console.log('discovered ' + u);
color[u] = 'grey';
d[u] = ++this.time;
var g = this;
/* neighbor */
this.adjList.get(u).forEach(function(w) {
if (color[w] === 'white') {
p[w] = u;
g.DFSVisit(w, color, d, f, p);
}
});
color[u] = 'black';
f[u] = ++this.time;
console.log('explored ' + u);
}
};
Graph.printNode = function(value) {
console.log('visited vertex: ' + value);
};
exports.Graph = Graph;
* TestGraph.js
/**
* Created by Mch on 9/2/18.
*/
var Graph = require('./Collection/Graph').Graph;
var graph = new Graph(),
myVertices = ['A','B','C','D','E','F','G','H','I'];
myVertices.forEach(function(v) {
graph.addVertex(v);
});
graph.addEdge('A', 'B'); //{9}
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());
graph.bfs(myVertices[0], Graph.printNode);
var shortestPathA = graph.BFS(myVertices[0]);
console.log(shortestPathA);
console.log('--------------------------');
graph.dfs(Graph.printNode);
var result = graph.DFS();
console.log(result);
* run:
$ node TestGraph.js
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
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
{ distances: [ A: 0, B: 1, C: 1, D: 1, E: 2, F: 2, G: 2, H: 2, I: 3 ],
predecessors:
[ A: null,
B: 'A',
C: 'A',
D: 'A',
E: 'B',
F: 'B',
G: 'C',
H: 'D',
I: 'E' ] }
--------------------------
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
discovered A
discovered B
discovered E
discovered I
explored I
explored E
discovered F
explored F
explored B
discovered C
discovered D
discovered G
explored G
discovered H
explored H
explored D
explored C
explored A
{ discovery: [ A: 1, B: 2, C: 10, D: 11, E: 3, F: 7, G: 12, H: 14, I: 4 ],
finished: [ A: 18, B: 9, C: 17, D: 16, E: 6, F: 8, G: 13, H: 15, I: 5 ],
processors:
[ A: null,
B: 'A',
C: 'A',
D: 'C',
E: 'B',
F: 'B',
G: 'D',
H: 'D',
I: 'E' ] }