知乎主页https://www.zhihu.com/people/shuang-shou-cha-dai-53
目录
1:Dijkstra算法
1.1:算法思想
1.2:算法步骤
1.3:代码演示
1.4:算法实例
1.4:算法优缺点
2:A* 算法
2.1:算法思想
2.2:算法步骤
2.3:Dijkstras算法与A*算法的比较
3:Floyd算法
3.1:算法思想
3.2:算法步骤
3.3:算法实例
3.4:算法优缺点
迪杰斯特拉(Dijkstra)算法是典型的最短路径的算法,用来求得从起始点到其他所有点最短路径(单源最短路径)。该算法采用了贪心的思想,每次都查找与该点距离最近的点,可以看成是广度优先搜索,也因为这样,它不能用来解决存在负权边的图。解决的问题可描述为:在无向图 G=(V,E) 中,假设每条边 E[i] 的长度为 w[i],找到由顶点vs到其余各点的最短路径。
Dijkstra算法就是保证当前节点的值对于前面的层一定是最优的(不管后面有啥只往前看),所以最后到终点的时候,可以保证终点到前一层选一个最优的点,这样从终点到起点一直选当前最小得到的路径一定是最优的。
通过Dijkstra计算图G中的最短路径时,需要指定起点vs(即从顶点vs开始计算)。此外,引进两个集合S和U。S的作用是记录已求出最短路径的顶点(以及相应的最短路径长度),而U则是记录还未求出最短路径的顶点(以及该顶点到起点vs的距离)。初始时,S中只有起点vs;U中是除vs之外的顶点,并且U中顶点的路径是"起点vs到该顶点的路径"。然后,从U中找出路径最短的顶点,并将其加入到S中;接着,更新U中的顶点和顶点对应的路径。 然后,再从U中找出路径最短的顶点,并将其加入到S中;接着,更新U中的顶点和顶点对应的路径。重复该操作,直到遍历完所有顶点。
'''
dijkstra algorithm demo
graph size:6*6
node index start from 0
'''
import numpy as np
graph_list = [[0, 2, 1, 4, 5, 1],
[1, 0, 4, 2, 3, 4],
[2, 1, 0, 1, 2, 4],
[3, 5, 2, 0, 3, 3],
[2, 4, 3, 4, 0, 1],
[3, 4, 7, 3, 1, 0]]
def dijkstra(graph, src):
# init
visited = []
distance = {src: 0}
node = list(range(len(graph[0])))
if src in node:
node.remove(src)
visited.append(src)
else:
return None
for i in node:
distance[i] = graph[src][i]
prefer = src
while node:
_distance = float('inf')
for i in visited:
for j in node:
if graph[i][j] > 0:
if _distance > distance[i] + graph[i][j]:
_distance = distance[j] = distance[i] + graph[i][j]
prefer = j
visited.append(prefer)
node.remove(prefer)
return distance
if __name__ == '__main__':
distance = dijkstra(graph_list, 0)
print(distance)
下图是一个无向图,演示Dijkstra的步骤
Dijkstra算法找出以A为起点的单源最短路径计算过程如下:
A*算法作为Dijkstra算法的扩展,是一种静态路网中求解最短路最有效的方法,在机器人、导航、游戏等领域有着广泛应用。A* 作为 Dijkstra 的改进版,目的就在于解决 Dijkstra 效率低下的问题,上面提到 Dijkstra 算法是计算单源节点到所有节点的距离,即:要遍历所有节点,在不知道目标节点的位置时,它只能向所有可能的方向扩展节点直到发现目标节点为止。
A* 算法在 Dijkstra 的基础上引入了启发式函数 h(n),h(n)表示了当前节点到目标节点的成本。保证了最优性的同时,加入了目标节点的信息,提升了搜索效率。
公式表示为:f(n)=g(n)+h(n), 其中f(n) 是节点n从初始点到目标点的估价函数,g(n) 是在状态空间中从初始节点到n节点的实际代价,即起始节点到当前节点的实际代价.
h(n)是从n到目标节点最佳路径的估计代价。即当前节点到目标节点的估计代价。
g(n):对g*(n)的一个估计,是当前的搜索图G中s到n的最优路径费用 g(n)≥g*(n)。
h(n):对h*(n)的估计,是从n到目标节点的估计代价,称为启发函数。
下面为Dijkstra 算法(没有用到启发式策略)动画演示,其中{ 绿色:起点 红色:终点 黑色:障碍物 白色:路径 黄色:已处理的节点 }
下面是A* 算法的动画演示(使用了启发式信息:到目标的距离)
与Dijkstra 算法相比,A* 算法由于引入了启发函数 h(n),所以它拓展节点的时候具有一定目的性(即向目标节点的方向扩展),所以它搜索目标节点时所需要扩展的中间节点更少,因此算法效率更高。
Floyd算法,是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法,与Dijkstra算法类似。简单的说就是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径问题,同时也被用于计算有向图的传递闭包。Floyd算法的时间复杂度为O(N3),空间复杂度为O(N2)。
Floyd算法定义了两个二维矩阵:
它通过3重循环,k为中转点,v为起点,w为终点,循环比较D[v][w] 和 D[v][k] + D[k][w] 最小值,如果D[v][k] + D[k][w] 为更小值,则把D[v][k] + D[k][w] 覆盖保存在D[v][w]中。
上述概念理解起来比较晦涩,直接以一个图例中的最短路径来说明Floyd算法步骤:
优点:容易理解,可以算出任意两个节点之间最短距离的算法,程序容易写;
缺点:复杂度达到三次方,不适合计算大量数据,它需要用邻接矩阵来储存边,这个算法通过考虑最佳子路径来得到最佳路径。注意单独一条边的路径也不一定是最佳路径。
知乎主页https://www.zhihu.com/people/shuang-shou-cha-dai-53https://www.zhihu.com/people/shuang-shou-cha-dai-53