图是网络结构的抽象模型。图是一组由边连接的节点(或顶点)。

在实现BFS算法之前,先建立邻接矩阵和邻接表:

邻接矩阵

每个节点都和一个整数相关联,该整数将作为数组的索引。用一个二维数组来表示顶点之间的连接。比如上面图片中的图的邻接矩阵表示:

由于该图不是强连通图(如果图中每两个顶点间在双向上都存在路径,则该图是强连通的。例如, C和D是强连通的,而A和B不是强连通的。),所以在矩阵中会出现‘0’值,表示该两节点之间没有连接。、

但是,图中顶点的数量可能会改变,而2维数组不太灵活。一般会选择使用邻接表

邻接表

动态数据结构,邻接表由图中每个顶点的相邻顶点列表所组成。

两者的不同

1、在邻接矩阵表示中,无向图的邻接矩阵是对称的。矩阵中第 i 行或 第 i 列有效元素个数之和就是顶点的读。

在有向图中 第 i 行有效元素个数之和是顶点的出度,第 i 列有效元素个数之和是顶点的入度。

2、在邻接表的表示中,无向图的同一条边在邻接表中存储的两次。如果想要知道顶点的读,只需要求出所对应链表的结点个数即可。

有向图中每条边在邻接表中只出现一此,求顶点的出度只需要遍历所对应链表即可。求出度则需要遍历其他顶点的链表。

3、邻接矩阵与邻接表优缺点:

邻接矩阵的优点是可以快速判断两个顶点之间是否存在边,可以快速添加边或者删除边。而其缺点是如果顶点之间的边比较少,会比较浪费空间。因为是一个 n∗nn∗n 的矩阵。

而邻接表的优点是节省空间,只存储实际存在的边。其缺点是关注顶点的度时,就可能需要遍历一个链表。还有一个缺点是,对于无向图,如果需要删除一条边,就需要在两个链表上查找并删除。

demo函数创建

创建空图

使用字典进行储存数据,字典中的键值对可以更好地存储节点的信息。字典源码:Javascript实现Dictionary

添加边和顶点的信息

使用push()方法进行添加,图中的有向图和无向图创建的区别就是无向图两个节点之间是互相连通的,对于有向图是单向的。

输出函数toString

测试邻接表

BFS算法

在BFS算法中,使用队列进行节点信息的存储:通过将顶点存入队列中(在第4章中学习过),最先入队列的顶点先被探索。

BFS搜索路径:

  • 创建 BFS 步骤
  • (1) 创建一个队列Q。
  • (2) 将v标注为被发现的(灰色),并将v入队列Q。
  • (3) 如果Q非空,则运行以下步骤:
  • (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'; //赋值 white 表示没有被访问过}return color;
};

BFS核心demo

创建BFS算法,使用队列。队列源码:Javascript实现Queue

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++) { // 对u的每个邻点var w = neighbors[i]; // 取值if (color[w] === 'white') { // 如果没有进行访问color[w] = 'grey'; // 标记访问queue.enqueue(w); // 将该顶点加入队列中}}color[u] = 'black'; // 已经访问并已经探索完成if (callback) { // 回调函数...callback(u);}}
};

实现及解释过程在以上源码中。

测试之前的图,并输出BFS节点访问顺序:

BFS算法实现最短路径

给定一个图G和源顶点v,找出对每个顶点u, u和v之间最短路径的距离。对于给定顶点v,广度优先算法会访问所有与其距离为1的顶点,接着是距离为2的顶点,以此类推。

创建两个数组:

  • 从v到u的距离d[u];
  • 前溯点pred[u],用来推导出从v到其他每个顶点u的最短路径。

改进之后的算法

for (var i = 0; i < vertices.length; i++) { //循环遍历数组赋值d[vertices[i]] = 0; //用0来初始化数组d  表示距离pred[vertices[i]] = null; //null来初始化数组pred   存储前溯点
}
while (!queue.isEmpty()) { //队列非空var u = queue.dequeue(), //操作队列,从中移除一个顶点neighbors = adjList.get(u); //取得包含所有邻点的邻接表color[u] = 'grey'; // 表示已经访问但未探索for (var i = 0; i < neighbors.length; i++) { // 对u的每个邻点var w = neighbors[i]; // 取值if (color[w] === 'white') {color[w] = 'grey';d[w] = d[u] + 1; //给d[u]加1来设置v和w之间的距离pred[w] = u; //顶点u的邻点w时,则设置w的前溯点值为uqueue.enqueue(w);}}color[u] = 'black';
}

我声明数组d来表示距离,以及pred数组来表示前溯点。下一步则是对图中的每一个顶点,用0来初始化数组d,用null来初始化数组pred。当发现顶点u的邻点w时,则设置w的前溯点值为u。还通过给d[u]加1来设置v和w之间的距离(u是w的前溯点, d[u]的值已经有了)。方法最后返回了一个包含d和pred的对象。

测试改进后的BFS算法

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');function printNode(value) {console.log('Visited vertex: ' + value); //输出值
}
graph.bfs(myVertices[0], printNode); //调用函数
var shortestPathA = graph.BFS(myVertices[0]);
console.log(shortestPathA);

输出如下(根据BFS的搜索特点,存储相应的节点距离和前溯点的信息):

输出最短路径

var finalVertexPath = myVertices[0]; //顶点A作为源顶点
for (var i = 1; i < myVertices.length; i++) { //从1开始,去除A节点即源节点var toVertex = myVertices[i], //顶点数组得到toVertexpath = new Stack(); //创建一个栈存储路径值for (var v = toVertex; v !== finalVertexPath; v = shortestPathA.predecessors[v]) { //追溯toVertex到finalVertexPath的路径path.push(v); //变量v添加到栈中}path.push(finalVertexPath); //最后添加源顶点var s = path.pop(); //弹出源定点while (!path.isEmpty()) { s += ' - ' + path.pop(); //栈中移出一个项并将其拼接到字符串s的后面}console.log(s); //输出路径
}

最终的最短路径输出:

BFS源代码:JavaScript实现BFS

时间复杂度

BFS是一种借用队列来存储的过程,分层查找,优先考虑距离出发点近的点。无论是在邻接表还是邻接矩阵中存储,都需要借助一个辅助队列,n个顶点均需入队,最坏的情况下,空间复杂度为O(n)。

邻接表形式存储时,每个顶点均需搜索一次,时间复杂度T1=O(n),从一个顶点开始搜索时,开始搜索,访问未被访问过的节点。最坏的情况下,每个顶点至少访问一次,每条边至少访问1次,这是因为在搜索的过程中,若某结点向下搜索时,其子结点都访问过了,这时候就会回退,故时间复 杂度为O(E),算法总的时间复 度为O(|N|+|E|)。

邻接矩阵存储方式时,查找每个顶点的邻接点所需时间为O(N),即该节点所在的该行该列。又有N个顶点,故算总的时间复杂度为O(|N|^2)。

Javascript实现BFS算法相关推荐

  1. 学习JavaScript 数据结构与算法

    学习链接:https://github.com/XPoet/js-data-structures-and-algorithms JavaScript 数据结构与算法 1.数据结构(data struc ...

  2. JavaScript数据结构与算法(2)(集合、字典、哈希表、二叉树、图)(ES6)

    注意:原教学视频:JavaScript(ES6)数据结构和算法 | JavaScript数据结构与算法 (都是CoderWhy老师的教学) 原作者(笔记)链接:JavaScript 数据结构与算法 | ...

  3. 学习JavaScript数据结构与算法(一):栈与队列

    本系列的第一篇文章: 学习JavaScript数据结构与算法(一),栈与队列 第二篇文章:学习JavaScript数据结构与算法(二):链表 第三篇文章:学习JavaScript数据结构与算法(三): ...

  4. 广度优先搜索 BFS算法

    广度优先搜索算法(Breadth-First-Search,BFS),又称作宽度优先搜索.BFS算法是从根节点开始,沿着树的宽度遍历树的节点.如果所有节点均被访问,则算法中止. 算法思想 1.首先将根 ...

  5. javascript数据结构与算法---检索算法(二分查找法、计算重复次数)

    javascript数据结构与算法---检索算法(二分查找法.计算重复次数) /*只需要查找元素是否存在数组,可以先将数组排序,再使用二分查找法*/ function qSort(arr){if (a ...

  6. JavaScript数组去重算法实例

    本文主要介绍了JavaScript数组去重算法,结合实例形式总结分析了JavaScript数组去重相关的读写.遍历.比较.排序等操作及算法改进相关实现技巧,需要的朋友可以参考下 测试用例: arr = ...

  7. 为什么我要放弃javaScript数据结构与算法(第二章)—— 数组

    第二章 数组 几乎所有的编程语言都原生支持数组类型,因为数组是最简单的内存数据结构.JavaScript里也有数组类型,虽然它的第一个版本并没有支持数组.本章将深入学习数组数据结构和它的能力. 为什么 ...

  8. BFS 算法解题套路框架+几个用于BFS的set与queue用法和技巧

    BFS 算法解题套路框架 几个用于BFS的set与queue用法和技巧(set查找visited queue正常用) queue<int>q; set<string>s; in ...

  9. JavaScript实现z-algorithm算法(附完整源码)

    JavaScript实现z-algorithm算法(附完整源码) zAlgorithm.js完整源代码 zAlgorithm.test.js完整源代码 zAlgorithm.js完整源代码 const ...

最新文章

  1. windows mysql dump_mysql在Windows下使用mysqldump命令手动备份数据库和自动备份数据库...
  2. leetcode算法题--Queue Reconstruction by Height
  3. 一个aov网用邻接矩阵表示_一起看看啥是图论算法-第一期:图的基本表示
  4. Linux疑难杂症解决方案100篇(十五)-万字长文带你深入Linux 内核学习:环境搭建和内核编译
  5. idea加入springboot插件_带你搭一个SpringBoot+SpringData JPA的环境
  6. uniCloud服务空间免费云存储图床系统源码
  7. oracle 批量杀死 死锁进程
  8. iOS开发的几种加密方式
  9. python基础案例教程课后答案_Python基础案例教程
  10. 云计算 概念 是什么
  11. CSPNet: A New Backbone that can Enhance Learning Capability of CNN
  12. Matplotlib填充色Colormap
  13. Python—获取电脑的锁屏壁纸
  14. Excel 快速合并多行数据为一行
  15. 解决联想笔记本E40 安装VM虚拟机后每次启动都会导致电脑蓝屏问题
  16. ogr2ogr导入导出数据。
  17. python列表中获取最长的字符串
  18. Python-项目实战-《外星人入侵》Pygame小游戏-阶段二:外星人来了
  19. Unity虚拟天文馆
  20. echarts中tooltip前面的小圆点

热门文章

  1. 何恺明一作,刷新7项检测分割任务,无监督预训练完胜有监督
  2. 视觉推理新杀器!英特尔新一代VPU性能翻10倍,反超英伟达
  3. 是时候学习生成对抗网络了,李宏毅老师GAN视频教程下载
  4. 计算机视觉研究入门全指南
  5. mysql 实现非递归树_二叉树的非递归前序,中序,后序遍历算法
  6. python哪几种开源框架成为大主流【菜鸟必看】
  7. mysql5.6 with as 用法_python面试专题with 关键字与上下文管理
  8. 【资源下载】 UC 伯克利 Chelsea Finn 博士论文(新起之秀——MAML)《Learning to Learn with Gradients》下载--2018ACM最佳博士论文下载
  9. 系统无法执行指定的程序。_使用Rust编写操作系统(一):独立式可执行程序
  10. 设计模式 过滤器模式