广度优先查找无向无权图两点间最短路径,可以将图看成是以起点为根节点的树状图,每一层是上一层的子节点,一层一层的查找,直到找到目标节点为止。

起点为0度,与之相邻的节点为1度,以此类推。

    // 广度优先遍历查找两点间最短路径
breadthFindShortestPath(sourceId, targetId) {
const { nodesKV } = this.chart.getStore();
let visitedNodes = []; // 出现过的节点列表
let degreeNodes = [[sourceId]]; // 二维数组,每个数组是每一度的节点列表。1度就是起点
let degree = 0; // 当前查找的度数
let index = 0; // 当前查找的当前度数节点数组中的索引
let nodesParent = {}; // 记录每个节点的父节点是谁。广度优先遍历,每个节点就只有一个父节点
let pathArr = []; // 最短路径 visitedNodes.push(sourceId); outer:
while (degreeNodes[degree][index]) { degreeNodes[degree + 1] = degreeNodes[degree + 1] || []; // 初始化下一度 const node = nodesKV[degreeNodes[degree][index]];
const neighborNodes = [...node.children || [], ...node.parents || []]; for (let i = 0; i < neighborNodes.length; i++) {
const id = neighborNodes[i];
// 如果找到了,则退出
if (id === targetId) {
nodesParent[id] = degreeNodes[degree][index]; // 记录目标节点的父节点是谁
break outer;
} else if (!visitedNodes.includes(id)) { // 如果没有找到,并且这个节点没有访问过,则把它添加到下一度中
visitedNodes.push(id);
degreeNodes[degree + 1].push(id);
nodesParent[id] = degreeNodes[degree][index];
}
} // 如果当前节点后面还有节点,则查找后一个节点
if (degreeNodes[degree][index + 1]) {
index++;
} else {
degree++;
index = 0;
}
} // 通过目标节点的父节点,层层追溯找到起点,得到最短路径
let nodeId;
nodeId = targetId;
while (nodeId) {
pathArr.push(nodeId);
// 当前节点有父节点,则将 nodeId 设置为父节点的 id,继续循环查找父节点
if (nodesParent[nodeId]) {
pathArr.push(nodesParent[nodeId]);
nodeId = nodesParent[nodeId]; // nodeId 设置为父节点的 id
} else { // 没有父节点,则说明到了起点。nodeId 设为 null,退出循环
nodeId = null;
}
} return pathArr;
}

上面代码中,主要的数据结构有:

visitedNodes:一层层的查找,出现的节点立刻添加到这个数组中。当查找一个节点的相邻节点时,如果相邻节点是它的父节点或同一度的节点,那这个节点就已经在 visitedNodes 中了,不会将此节点标记为这个节点的子节点。

degreeNodes:数组中的每个数组,就是0度至N度,每一度的节点列表。

nodesParent:查找节点时,会将当前节点标记为相邻节点的父节点(除了已经在 visitedNodes 中的,visitedNodes 中的节点都已有了父节点),每个节点只有一个父节点。

假设下图中1号节点为开始节点,15号节点为目标节点:

情况分析:

1、1号节点开始查找,找到相邻节点2,3,4,5号,2,3,4,5号节点都没在 visitedNodes 中,将它们添加到 visitedNodes 里,并且将它们添加到 degreeNodes 中下一度的数组中。此时 visitedNodes 里面就有1,2,3,4,5号节点,nodesParent 里面,2,3,4,5号节点的父节点都是1号节点。

2、1号节点后面没有与之同度数的节点,degree 加1,index 重置为0。

3、2号节点开始查找,相邻节点中有1,3,6,7,8号节点,图中可以看出1号节点和3号节点是它的父节点和同度数的节点,这两个节点已经被添加到了 visitedNodes 中,则只将6,7,8号节点添加到 degreeNodes 中下一度的数组中。nodesParent 里面,6,7,8号节点的父节点都设置为2号节点。visitedNodes 中添加6,7,8号节点。

4、2号节点的相邻节点遍历完成后,判断2号节点后面是否有相同度数的节点,degreeNodes[degree][index + 1] 发现不为空,则 index++ 继续循环查到当前度数的下一个节点的相邻节点。

5、开始查找3号节点的相邻节点,1,2,4,6,8,9号节点都是3号节点的相邻节点,而1,2,4,6,8号节点都已在 visitedNodes 中,则只将9号节点的父节点设置为3号节点。

6、同理,继续判断3号节点后是否有相同度数的节点,有4号节点,继续查找,有5号节点,继续查找。

7、当找到12号节点后,继续查找5号节点后是否有相同度数的节点,degreeNodes[degree][index + 1]  的值为 undefined 了,则 degree++, index = 0 继续循环找下一度的节点。

8、通过6号节点的相邻节点,找到了15号节点,此时退出循环,通过 nodesParent 得到最短路径 15-6-2-1。

当然,我们也能从图中看出1-3-6-15,1-3-9-15和1-5-9-15也是最短路径,不过这不重要,找到一条即可。这也是为什么 nodesParent 里面6号节点的父节点只设置2号而不用设置3号,一个节点只设置一个父节点,因为无论从哪个父节点查找,路径长度是一样的。

JS广度优先查找无向无权图两点间最短路径的更多相关文章

  1. hdu 2544 最短路(两点间最短路径)

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=2544 方法一:dijkstra算法,求两点之间最短路径. /*********************** ...

  2. AOJ GRL_1_C: All Pairs Shortest Path (Floyd-Warshall算法求任意两点间的最短路径)(Bellman-Ford算法判断负圈)

    题目链接:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_1_C All Pairs Shortest Path Input ...

  3. [CF1051F]The Shortest Statement (LCA+最短路)(给定一张n个点m条有权边的无向联通图,q次询问两点间的最短路)

    题目:给定一张n个点m条有权边的无向联通图,q次询问两点间的最短路 n≤100000,m≤100000,m-n≤20. 首先看到m-n≤20这条限制,我们可以想到是围绕这个20来做这道题. 即如果我们 ...

  4. SpringMVC结合ajaxfileupload.js实现文件无刷新上传

    直接看代码吧,注释都在里面 首先是web.xml <?xml version="1.0" encoding="UTF-8"?> <web-ap ...

  5. 原生JS面向对象思想封装轮播图组件

    原生JS面向对象思想封装轮播图组件 在前端页面开发过程中,页面中的轮播图特效很常见,因此我就想封装一个自己的原生JS的轮播图组件.有了这个需求就开始着手准备了,代码当然是以简洁为目标,轮播图的各个功能 ...

  6. 算法笔记_021:广度优先查找(Java)

    目录 1 问题描述 2 解决方案 2.1 蛮力法 1 问题描述 广度优先查找(Breadth-first Search,BFS)按照一种同心圆的方式,首先访问所有和初始顶点邻接的顶点,然后是离它两条边 ...

  7. Java实现BFS广度优先查找

    1 问题描述 广度优先查找(Breadth-first Search,BFS)按照一种同心圆的方式,首先访问所有和初始顶点邻接的顶点,然后是离它两条边的所有未访问顶点,以此类推,直到所有与初始顶点同在 ...

  8. 图中两点间路径为l的数目

    用矩阵G表示图的邻接阵. G2中的元素就是两点间路径为2的路径数,同理G3就是两点间路径为3的路径数目. 并且此结论同样适用于有向图. 甚至,此结论适用于有权图,只是算出来的不再是路径数,而是各条路径 ...

  9. Js实现京东无延迟菜单效果(demo)

    一个端午节,外面人山人海,又那么热,我认为宅在家里看看慕课网,充实自己来的实际... 这是一个js实现京东无延迟菜单效果,感觉很好,分享给大家... 1.开发基本的菜单结构 2.开发普通的二级菜单效果 ...

随机推荐

  1. ECharts简单入门demo

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  2. DX使用随笔--NavBarControl

    1. Item图标大小显示 需要先设置此Item所在Group的属性GroupStyle的值为LargeImageText.

  3. 一个SAP顾问的回忆:我过去很胖!

    去年也是这个时候,SAP成都研究院体育界大神邓阳,曾经赏脸在Jerry这个公众号上赐文一篇,介绍了他和围绕在他身边的一群小伙伴们的体育故事:SAP成都研究院的体育故事 而今天文章的主角则是SAP成都研 ...

  4. 6.SpringMVC 配置式开发-处理器

    处理器除了实现Controller 接口外,还可以继承自一些其他的类,来完成一些特殊的功能 1.继承自AbstractController类 若处理器继承自AbstractController类,那么 ...

  5. 6.B+Tree 检索原理

    B+树的创建(索引的创建) 1.比如为phoneNum创建了一个索引,phoneNum这列保存了很多的手机号码 2.索引创建的过程中,会为这些数据进行适当的编码(根据这个数据所在的物理地址),如 36 ...

  6. java EE,java Web中的400,404,405等各种错误介绍

    4 请求失败4xx 4xx应答定义了特定服务器响应的请求失败的情况.客户端不应当在不更改请求的情况下重新尝试同一个请求.(例如,增加合适的认证信息).不过,同一个请求交给不同服务器也许就会成功. 4. ...

  7. spring 整合mongodb报NoSuchMethodError错误

    刚开始通过网上查到相关的资料进行了一些配置,参考链接:http://www.open-open.com/lib/view/open1454374782167.html maven的dependenci ...

  8. 03_Hive的交互方式

    之前使用的Shell方式只是Hive交互方式中的一种,还有一种就是将Hive启动为服务运行在一个节点上,那么剩下的节点 就可以使用客户端来连接它,从而也可以使用Hive的数据分析服务 1.Hive的交 ...

  9. anaconda环境中---py2.7下安装tf1.0 + py3.5下安装tf1.5

    anaconda环境中---py2.7下安装tf1.0 + py3.5下安装tf1.5 @wp20181030 环境:ubuntu18.04, anaconda2, ubuntu系统下事先安装了pyt ...

  10. 一步步实现ArcMenu效果

    先来看一下最终要实验的效果: 是不是跟国外的一款Path的菜单效果类似,这里的动画采用补间动画去实现,正而操练一下补间动画. 布局和子视图的测量处理: 新建一自定义View继承ViewGroup: 然 ...