本文是博主深感算法方面的不足,做的一系列读书笔记和源码分析。
原文地址:学习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复制代码
本文对你有帮助?欢迎扫码加入前端学习小组微信群: