Dijkstra算法
Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,即计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。注意该算法要求图中不存在负权边。
算法描述
在无向图 G=(V,E) 中,要求v0到其余各顶点的最短距离,这里将图中的顶点在计算过程中分为已确定最短路径的顶点集合(T),和目前并不确定最短路径的顶点集合(U)。在当前已经确定的最短路径集合中向外扩展,依次把U中距离v0最短的顶点并入T,并且每次在并入新顶点时更新以新顶点最为中介点,v0到其余各点的距离。如此,遍历至最后一点可找出V0到各顶点的最短距离。
基本执行分三步
<1>找出当前V0到各顶点的最短距离,并记录这条边的终点,和长度。
<2>将<1>中终点并入T(代码中s集合对应点标记为1)。
<3>以新并入的点作为中介点,更新此时V0到各顶点的最短距离。重复上述步骤直至到最后一点,即可得V0到图中所有顶点的最短距离。
举个简单的例子:计算下图中顶点1到图中任一点的最短距离。
源代码(python):
if __name__ == '__main__':
maxInt = 999999
v0 = 1
data = [[0, 1, 2, 3, 4, 5, 6], # 数集下表对应点集下标,第零行和第零列为行列序号
[1, 0, 7, 9, 0, 0, 14],
[2, 7, 0, 10, 15, 0, 0],
[3, 9, 10, 0, 11, 0, 2],
[4, 0, 15, 11, 0, 6, 0],
[5, 0, 0, 0, 6, 0, 9],
[6, 14, 0, 2, 0, 9, 0]]
dis = [0, 0] # 记录定点到图中各点的最短距离
s = [0, 1, 0, 0, 0, 0, 0] # 标志点分集,0表示在U集合,1表示在T集合
for i in range(2, 7):
if data[v0][i] == 0:
dis.append(maxInt)
else:
dis.append(data[v0][i])
for m in range(1, 7): # 查找U集合中每一点到V0最短距离
mindis = maxInt
u = v0
for k in range(1, 7):
if not s[k] and dis[k] < mindis:
mindis = dis[k]
u = k
s[u] = 1 # 记录当前能并入T中最短距离的点
for j in range(1, 7): # 以新并入的点为中间点更新最短距离集合
if not s[j] and data[u][j] and (dis[u] + data[u][j]) < dis[j]:
dis[j] = dis[u] + data[u][j]
print(dis)
运行结果:
负权值不适用
如下图所示的情况:
原来是这样的,本来全为正值的时候,只要每次保证都是加入的最短路径,那么直至最后一定能保证计算结果为最短的。然,不幸的是中间出现了负权值,导致从一开始加入的最短路径的做法并不一定是最优的,而现在的算法却只有按照并入的点往上加,而无法退回去重新算一下原来计算出的结果。