Dijkstra 算法案例、局限性和 Java 代码实现
Dijkstra 算法(Dijkstra)用于在没有非负权重的情况下计算从起点到每个节点的最短距离
可用 2 类问题: 有从 A 地到 B 地的路吗?
思路是:
(1)找到“最便宜”的节点,即最短时间可以到达的节点。
(2)更新该节点对应的邻居节点的cost,其含义稍后介绍。
(3) 重复此过程,直到对图中的每个节点都完成此操作。
(4) 计算最后一条路径。
案例
案例一
我们举一个简单的例子来介绍一下其实现的思路:
如下图,得到从起点到终点的最短路径。算法思想
1.首先列出每个节点花费的起点和终点时间:
| 父节点 | 节点 | 花费的时间 |
|---|---|---|
| 起点 | ||
| 出口点 B2分钟。 . | 终点 | ∞被视为无穷大 |
2。获取最便宜的节点。从上表我们知道起点->B成本最低。计算B节点到各个邻居节点所花费的时间,更新耗时较多的原节点:
| 父节点 | 节点 | 耗时B5分钟更新时间,本来已经持续了6分钟3。此时B就被添加到已处理列表中,不再进行处理。现在至少还剩下起点->E成本,计算节点A走到所有邻居节点所需要的时间,并更新原来花费时间较多的节点:
4。这时,我们可以通过倒序知道:起点->A->终点,这条路径是最短路径,耗时6分钟 情况2这里是前面广度优先搜索的例子算法: 如上图所示,可以利用广度优先搜索算法来求从A到H的最小步数。路径为:A->B->E->H。这次将每条路线所需的时间相加(当然也可以代表公里数)作为每条路段的权重。 现在A->B->E->H显然不再是最短路径。这个通过添加权重来寻找最短路径的问题可以用Dijkstra算法来解决: 1。获取A在各个节点上花费的时间,A标记为已处理:
2。找到A能到达的最短节点,并计算更新相邻节点所需的时间。这是最短的一个。 5分钟 | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| A | C | 1分钟 | C已处理 | |||||||||||||||
| C | D |
F
... H
| 父节点 | 节点 | 耗时标记 | 5分钟 | B 处理 | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| A | C 1 分钟 | C 处理 | ||||||||||||||||||||
| CD6 C | F | 7 分钟 | ||||||||||||||||||||
| B | E15 分钟 | |||||||||||||||||||||
| .. | H | ∞ 被视为无穷大∞。 A的邻接节点已被处理。此时,求C能到达的最短节点。此时是C->D。计算更新相邻节点所需的时间。 D 标记为已处理
4. 以同样的方式更新父节点 | 节点 | 标志 | ||||||||||||||||||
| A B已处理 | ||||||||||||||||||||||
| C | C | C 已处理 1 分钟 D G | 9 分钟 | ∞ 被视为无穷大 |
4。同样更新E
| 父节点 | 节点 | 花费时间 | 标志 |
|---|---|---|---|
| A 5分钟 | B 已处理 | ||
| A | C 1 分钟。 F | 7分钟 | F处理 |
| D9分钟12分钟 |
5.同样更新G
| 父节点 | 节点 | 耗时 | 标志 |
|---|---|---|---|
| AB 5分钟 | B已处理 | ||
| A | C 1 分钟 C已处理 | ||
| C | D6 分钟 |
D F
经过上述步骤,我们可以逆序得到最短路径:
A->H。最短路线为:A->C->D->E->H,共需要12分钟;表中的其余结果也是最短的。路径,如A->G最短路径:A->C->F->G
局限性
该算法不适合负权重。情况3:
这里我们用这个算法来看看为什么不合适,计算A->E:
1。首先从起点A开始
| 父节点 | 节点 | 耗时 | |
|---|---|---|---|
| A | B00 A C | 1元..终点 | ∞ 被视为无穷大 |
2。计算最便宜的节点C
| parentnode | node耗时 | logo | ||
|---|---|---|---|---|
| AB100元 | ||||
| A C | 100元C已处理完毕。 c | d | 2元 | |
| ... | e点无限 |
2.计算最便宜的节点B
| 父节点 | 节点 | 耗时 | 标志 | |
|---|---|---|---|---|
| ABA100元 | B 已处理 | C C -100元C已经处理完毕,但这里还需要更新。 | 端点 ∞ 被视为无穷大 |
3。最便宜节点D
| 父节点 | 节点 | 计算需要 | LOGO | |
|---|---|---|---|---|
| AA100元 B 已处理 | ||||
| B | C | -100元C已处理完毕,但这里还需要更新C | ||
| C | D♶和2 D | E | 3元 |
Dijkstra算法计算出的结果会是错误的A->C->D->E,花费3元。在Dijkstra算法中标记为已处理的节点意味着该节点没有其他更新。更便宜的方法。由于负权重的引入,这个原理不成立。在上述情况下,由于节点C已经被处理,所以C的内容必须再次更新,但相应地,C的后续子节点例如D可能存在。更新不同步,导致最终结果不正确。当然,也有可能计算是正确的。例如,如果上述第二种情况改为A->B = -50,则正确的最短路径可以计算为A --> B --> E --> H,成本为-37。
个人认为能不能计算正确,就看权重为负的节点是否再次更新,以及相邻节点是否还没有计算完毕。例如案例 3 B 先处理 C:
处理 B:
| 父节点 | 节点 | 耗时 B100元 B 加工中 | A C | -100元 | |
|---|---|---|---|---|---|
| .. |
处理C:
| 父节点 | 节点 | 耗时 | 标志 | |
|---|---|---|---|---|
| A | B100元加工 A | C | -100元 | C已采购 |
| C | D | -99元 | ||
| .. | 端点 |
端点在♿♿ at♿at
| 父节点 | 节点 | 耗时 | 标志 |
|---|---|---|---|
| A | B | 10 0元 A C 已处理 已处理 | |
| C | D-99元 | D已处理 | |
| D | E♿E❿此时,正确的路径是A->->C->D->E,赚98元 但这与Dijkstra相反,在某些情况下可能效率极低。所有 Dijkstra 算法都不应该与负权重一起使用。 总结1.广度优先算法BFS主要适用于在无权有向图中重新搜索步数最少的路径。如果方向图中有权重,则不再适用 2。迪杰斯特拉算法 Dijkstra 主要用于搜索带权有向图中的最短路径,但不适合权重为负的情况。对于环形图形,我个人的感觉和BFS是一样的。已处理的按钮被标记以避免进入无限循环。可以支持 3.算法的实现主要是为了避免缺乏更好的解,采用穷举法来解决问题。当节点数量极其庞大时,算法的优势凸显出来 Java实现 |
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网