先前我们利用广度优先搜寻,找到图中两节点之间的最短路径,其中所谓「最短」是指「经过最少的边」。可是这样的路径却未必是最快路径,因为现实生活中不会每条路径的距离或交通状况都一样。如果想要像一个聪明的导航系统,找出最快的路径该怎麽做呢?
我们先想像在图的边上面加上数字,也就是所谓的权重(weight),边上有权重的图叫做赋权图或加权图(weighted graph)。权重可以视为是经过一条边所需的成本,在实际问题中它可以代表距离、时间、金钱等各种意义。
利用Dijkstra演算法,可以在赋权图中找出成本最低,即权重总和最小的路径,下述例子以距离最短表达,当然权重实际代表意义可能依问题改变。
Dijkstra演算法的方法是从起始节点开始,每次选择距离最近的节点,并且逐步更新起点到各节点的最短距离。
以上方的图来说,假设我们要从0到3,我们可以先把起始点到所有节点的距离暂时定为无穷远,因为目前尚不知道到任何节点的距离。
节点 | 起点到达该节点距离 |
---|---|
0 | 0 |
4 | 无穷远 |
1 | 无穷远 |
3 | 无穷远 |
2 | 无穷远 |
首先检查起点的邻居,若无目标节点,将起点与邻居的距离更新。
节点 | 起点到达该节点距离 |
---|---|
0 (已访问) | 0 |
4 | 20 |
1 | 10 |
3 | 无穷远 |
2 | 无穷远 |
接着进行几个步骤:
根据纪录,我们选择目前最近的节点1,起点经过节点1到邻居4, 3, 2的距离分别是60, 50, 40,接着可以更新表格。其中到达4的距离为60,并没有比原本的纪录20短,所以不更新。最後将1标为已访问。
节点 | 起点到达该节点距离 |
---|---|
0 (已访问) | 0 |
4 | 20 |
1 (已访问) | 10 |
3 | 50 |
2 | 40 |
接着选择当前最近的节点4,重复上面的步骤,有较短路径即更新表格。以4来说,经过4到达节点3的距离为90,不更新资料。
以此类推,最终直到目标节点3也被访问後,如下表格中0到3的距离50即是到目的地的最短距离。
节点 | 起点到达该节点距离 |
---|---|
0 (已访问) | 0 |
4 (已访问) | 20 |
1 (已访问) | 10 |
3 (已访问) | 50 |
2 (已访问) | 40 |
当然此处只是记录了距离,如果想要知道中间的路径,则可以每当更新最短距离的时候也记录该节点的父节点,最後由终点回溯每一个节点的父节点直到起点,即为最短距离的路径。例如更新节点1距离时记录父节点为0,更新节点3距离时记录父节点为1,最後从3回推最短路径为0-1-3
Dijkstra演算法还有很多的变化型,也可以用在有向图上,但基本上没有办法操作有权重为负值的图(除非多次访问节点,但这也就降低了执行效率)。要操作有负权重的图可以参考Bellman–Ford演算法。
Dijkstra演算法的执行时间取决於操作时的资料结构,如果是使用阵列来储存节点,执行时间为O(|V|²),但如果改成使用堆积,执行时间可以缩短为O(|E|+|V| log |V|)。
<<: # TypeScript 能手养成之旅 Day 15 介面(Interface)
>>: JavaScript学习日记 : Day21 - 数组方法(一)
JS背景 Javascript是由网景(Netscape)公司所开发的,当时网景公司的头号对手是微软...
前言 昨天我们成功开启相机并且回传相片,但我还没设定要回传到哪, 今天我一样要在不设定回传到哪的情况...
本文同步更新於blog Composite Pattern 允许将对象组合成树形结构来表现整体/部...
这篇开始使用 Html Helper 来 Render 出需要的 Html 控制项 name,方便在...
继续昨天的小教室。 我们在collectionviewcell的xib里,因为我们在主程序需要用到c...