最短路径算法
最短路径算法是用来在加权图中找到两个顶点之间的最短路径,即路径上的边的权重之和最小的问题。这里将介绍几种常见的最短路径算法:
1. Dijkstra算法
Dijkstra算法是一种广泛使用的最短路径算法,适用于处理带有非负权重的图。它通过贪心策略逐步确定从起点到图中所有其他顶点的最短路径。
算法步骤:
- 将起点的最短路径设为0,其他所有顶点的最短路径设为无穷大。
- 创建一个未访问顶点集合,包含所有顶点。
- 从未访问顶点集合中选择一个顶点(通常是具有当前已知最短路径的顶点)作为当前顶点。
- 将当前顶点从未访问集合中移除。
- 更新当前顶点的所有邻居顶点的最短路径。如果通过当前顶点到达邻居顶点的路径更短,则更新邻居顶点的最短路径。
- 重复步骤3-5,直到未访问顶点集合为空或找到目标顶点。
时间复杂度:
- 使用简单的数组和队列实现时,时间复杂度为O(V^2),其中V是顶点数。
- 使用优先队列(如二叉堆)可以优化到O((V+E)logV),其中E是边数。
2. Bellman-Ford算法
Bellman-Ford算法可以处理带有负权重边的图,但不能处理负权重循环。
算法步骤:
- 初始化所有顶点的最短路径为无穷大,起点的最短路径为0。
- 进行V-1次迭代,每次迭代更新图中所有边的最短路径。
- 如果在迭代中发现通过某个顶点可以找到更短的路径,则更新该路径。
- 检查是否存在负权重循环。可以通过进行额外一次迭代来检查,如果发现路径长度在这次迭代中仍然减少,则存在负权重循环。
时间复杂度:
- O(VE),适用于边数远大于顶点数的稀疏图。
3. Floyd-Warshall算法
Floyd-Warshall算法用于计算图中所有顶点对之间的最短路径。
算法步骤:
- 初始化一个矩阵,其中矩阵[i][j]表示顶点i到顶点j的最短路径长度。
- 对于每对顶点i和j,如果i直接到j的路径存在,则设置矩阵[i][j]为该路径的长度;否则设置为无穷大。
- 对于每个顶点k,更新矩阵,考虑通过顶点k进行路径转换的可能性。
- 如果矩阵[i][k] + 矩阵[k][j] < 矩阵[i][j],则更新矩阵[i][j]。
时间复杂度:
- O(V^3),适用于密集图。
4. A*搜索算法
A*算法是一种启发式搜索算法,通常用于图搜索和路径规划问题。它使用一个启发式函数来估计从当前顶点到目标顶点的距离。
算法步骤:
- 使用一个优先队列(通常是最小堆)来存储待扩展的顶点,优先级基于f(n) = g(n) + h(n),其中g(n)是从起点到顶点n的实际成本,h(n)是从顶点n到目标顶点的估计成本。
- 从起点开始,将起点加入优先队列。
- 当优先队列非空时,取出具有最低f(n)值的顶点。
- 如果取出的顶点是目标顶点,则找到了最短路径。
- 否则,将该顶点的所有邻居顶点加入优先队列,并更新它们的g(n)和f(n)值。
时间复杂度:
- 依赖于启发式函数的质量,理想情况下可以达到接近线性的时间复杂度。
每种算法都有其适用场景,选择哪种算法取决于具体问题的性质,如边的权重是否为非负、图的稠密程度、是否需要计算所有顶点对之间的最短路径等。
5.具体案例分析
示例:使用字典的方式构建有向图,并搜索图中的路径。
图很容易通过列表和词典来构造。比如说,这有一张简单的图:
A -> B
A -> C
A -> D
B -> E
C -> D
C -> F
D -> B
D -> E
D -> G
E ->
F -> D
F -> G
G -> E
这个图有7个节点(A-G)和12个弧。它可以通过下面的Python数据结构来表示:
graph = {‘A’: [‘B’, ‘C’,‘D’],
‘B’: [ ‘E’],
‘C’: [‘D’,‘F’],
‘D’: [‘B’,‘E’,‘G’],
‘E’: [],
‘F’: [‘D’,‘G’]
‘G’: [‘E’]}
6.完整代码实现
# 找到一条从start到end的路径
def findPath(graph,start,end,path=[]):
path = path + [start]
if start == end:
return path
for node in graph[start]:
if node not in path:
newpath = findPath(graph,node,end,path)
if newpath:
return newpath
return None
# 找到所有从start到end的路径
def findAllPath(graph,start,end,path=[]):
path = path +[start]
if start == end:
return [path]
paths = [] #存储所有路径
for node in graph[start]:
if node not in path:
newpaths = findAllPath(graph,node,end,path)
for newpath in newpaths:
paths.append(newpath)
return paths
# 查找最短路径
def findShortestPath(graph,start,end,path=[]):
path = path +[start]
if start == end:
return path
shortestPath = []
for node in graph[start]:
if node not in path:
newpath = findShortestPath(graph,node,end,path)
if newpath:
if not shortestPath or len(newpath)<len(shortestPath):
shortestPath = newpath
return shortestPath
# 主程序
graph = {'A': ['B', 'C','D'],
'B': [ 'E'],
'C': ['D','F'],
'D': ['B','E','G'],
'E': [],
'F': ['D','G'],
'G': ['E']}
onepath = findPath(graph,'A','G')
print('一条路径:',onepath)
allpath = findAllPath(graph,'A','G')
print('\n所有路径:',allpath)
shortpath = findShortestPath(graph,'A','G')
print('\n最短路径:',shortpath)
一条路径: ['A', 'C', 'D', 'G']
所有路径: [['A', 'C', 'D', 'G'], ['A', 'C', 'F', 'D', 'G'], ['A', 'C', 'F', 'G'], ['A', 'D', 'G']]
最短路径: ['A', 'D', 'G']