手把手教你区分Dijkstra算法和veterbi算法--图解

无论是Viterbi算法,还是Dijsktra算法,都是处理边权重图的最优路径问题。

Viterbi算法属于动态规划算法,Dijsktra算法属于贪心算法。Viterbi算法是广度优先,Dijsktra算法是深度优先。

一、Dijkstra算法

Dijkstra算法是典型的贪心算法,每次都寻找局部最优解最后达到全局最优!(不是所有的贪心算法都可以达到最优,看每种算法的设计)

我们需要一个辅助数组dist[]来存储最短路径长度,集合S来存储已经访问过的节点。

Diljstar的算法的步骤如下(这里使用*代替无穷):

1、假设我们要计算‘A’到其他节点的最短路径。首先我们就指定节点‘A’。

2、引入两个集合(S、U),S集合包含着已经求出的最短路径的点,U集合包含着还未求出的最短路径的点。

3、初始化上面两个集合,将A加入S集合,并计算‘A’点到其他节点的距离(直接相连的距离就是边的权值,未相连的为正无穷,其距离结果加入集合U),然后把除’A’点以外的所有节点加入集合U。

4、从集合U中选出距离‘A’节点最短的点,加入S集合,例如 A->D = 3。

5、更新U集合里的路径。如果D到其他节点的距离+ A->D距离 小于 A到其他节点的距离,则把D加入集合S。从U集合里删除D。

6、重复4、5步骤。直到遍历结束,得到A到其他节点的最短路径。

此步骤来自:知乎

是不是看不太懂,我们直接上图示:

我们先引入一个图
手把手教你区分Dijkstra算法和veterbi算法--图解
我们使用邻接矩阵来存储该图
手把手教你区分Dijkstra算法和veterbi算法--图解

第一步 S={1} (这里为了方便数组下标从1开始)只关注顶点1的出度

手把手教你区分Dijkstra算法和veterbi算法--图解
S(1-2) = 10 < * ,实现替换(S(1-2)指的是1-2的距离)
S(1-5) = 5 < * , 替换
手把手教你区分Dijkstra算法和veterbi算法--图解
我们选出Min{dist[]}的点加入集合S,此处Dist[5]最小。

第二步 S={1,5}只关注1,5的出度

手把手教你区分Dijkstra算法和veterbi算法--图解
S(1-5-2) < S(1-5), 替换
S(1-5-3) < * , 替换
S(1-5-4) < * ,替换
手把手教你区分Dijkstra算法和veterbi算法--图解
我们选出Min{dist[]}的点加入集合S,此处Dist[4]最小。

第三步 S={1,5,4}只关注1,5,4的出度

手把手教你区分Dijkstra算法和veterbi算法--图解
S(1-5-4-2) > S(1-5-2)=8, 不替换
S(1-5-4-3)=13 < S(1-5-3)=14, 替换
手把手教你区分Dijkstra算法和veterbi算法--图解
我们选出Min{dist[]}的点加入集合S,此处Dist[2]最小。

第四步 S={1,5,4,2}关注1,5,4,2的出度

手把手教你区分Dijkstra算法和veterbi算法--图解
手把手教你区分Dijkstra算法和veterbi算法--图解
我们选出Min{dist[]}的点加入集合S,此处Dist[3]最小。

第五步 S = {1,5,4,2,3},关注1,5,4,2,3的出度

手把手教你区分Dijkstra算法和veterbi算法--图解
此时S集合已经满了,算法结束,所以最短的结果分别为:

手把手教你区分Dijkstra算法和veterbi算法--图解
我们可以发现Dljkstra的算法的复杂度还是很高的,每一次S集合加入了新的顶点后就需要重新对dist[]路径长度进行更新。

但是值得庆幸的是不是每一次更新都需要更新全部的路径长度,而是更新为访问未的顶点的路径长度。

例如:
当S = {1}时, dist[]路径长度只需要更新2,3,4,5
当S = {1,5}时,dist[]路径长度只需要更新2,3,4

相信大家已经了解到Dijkstra算法的详细细节了,我们来看维特比算法是如何工作的

二、维特比算法

同样使用上图G
手把手教你区分Dijkstra算法和veterbi算法--图解
我们来看看维特比算法是如何体现广度搜索的思想的(以及动态规划)。

维特比算法将大问题分解成小问题,每一次都存储每一个小问题的最优结果。

这也是动态规划和递归的最大的区别,递归不会对子问题以及求解过的值进行存储,导致每次都需要重新计算,造成性能和资源的极大浪费。

第一次计算:
手把手教你区分Dijkstra算法和veterbi算法--图解
第二次计算:
手把手教你区分Dijkstra算法和veterbi算法--图解
终点出现多指向需要选出最短,在1-2-3和1-5-3中选出最短
变成:
手把手教你区分Dijkstra算法和veterbi算法--图解
第三次计算:
从次数开始计算量比较大,我们分解来看,前面一共有可能的最短路径是1-2-5,1-5-2,1-5-3,1-5-4

我们先看1-2-5:
手把手教你区分Dijkstra算法和veterbi算法--图解

再看1-5-2:
手把手教你区分Dijkstra算法和veterbi算法--图解

再看1-5-3:
手把手教你区分Dijkstra算法和veterbi算法--图解

再看1-5-4:
手把手教你区分Dijkstra算法和veterbi算法--图解

全部的连线为:(有点乱…)
手把手教你区分Dijkstra算法和veterbi算法--图解

终点出现多指向需要选出最短,所以选出最短得到:

手把手教你区分Dijkstra算法和veterbi算法--图解
所以得到结果:
手把手教你区分Dijkstra算法和veterbi算法--图解
手把手教你区分Dijkstra算法和veterbi算法--图解
到这里就完成了对维特比算法的图解了

参考:

如何通俗地讲解 viterbi 算法?