Dijkstra’s 算法
• 贪婪
• 使用优先级队列(heap)
• 列表中添加元素{元素,优先级},并从另一端删除最高优先级项
• 入队:添加一个{元素,优先级}
• 队列:删除最高优先级的元素
• 优先级队列通常使用“堆”来实现,并可以优先考虑低值(Min-Heap)或大值(Max-Heap)
缺点:边为负数,负循环等无法准确搜索。
# -*- coding: utf-8 -*-
# @Date : 2019/12/3
# @File : Dijkstra.py
from AdjListGraph import Graph, Vertex
import heapq
def shortest(vertex, path):
# 使用每个节点的previous回溯
if vertex.previous:
path.append(vertex.getVertexID())
shortest(vertex.previous, path)
return
def dijkstra(G, start, destination):
print("Dijkstra's shortest path")
# 起始点的距离为0, 其余的默认inf
start.setDistance(0)
unvisitedHeap = [(v.getDistance(), v) for v in G]
heapq.heapify(unvisitedHeap)
while len(unvisitedHeap):
# 第一次pop的为起始点的vertex(pop distance最小的节点)
unvisitedTuple = heapq.heappop(unvisitedHeap)
currentVertex = unvisitedTuple[1]
currentVertex.setVisited() # 置为访问过
# 遍历当前节点的neighbors. adjacent : Dict: Vertex:Weight # 当前节点的所有neighbors
for n in currentVertex.adjacent:
if n.visited:
continue
# 以当前节点为起(已经算的distance),到,邻居节点的distance(distance + weight/Edge)
newDistance = currentVertex.getDistance() + currentVertex.getWeight(n)
# 若这个新路径的距离小于原始neighbor的距离 则更新这个neighbor的距离
if newDistance < n.getDistance():
n.setDistance(newDistance)
n.setPrevious(currentVertex) # 当前neighbor的最小距离的来源父节点
print('Updated : current = %s next = %s newDist = %s' \
% (currentVertex.getVertexID(), n.getVertexID(), n.getDistance()))
else:
print('Not updated : current = %s next = %s newDist = %s' \
% (currentVertex.getVertexID(), n.getVertexID(), n.getDistance()))
while len(unvisitedHeap):
heapq.heappop(unvisitedHeap)
unvisitedHeap = [(v.getDistance(), v) for v in G if not v.visited]
heapq.heapify(unvisitedHeap)
if __name__ == '__main__':
G = Graph(True)
G.addVertex('a')
G.addVertex('b')
G.addVertex('c')
G.addVertex('d')
G.addVertex('e')
G.addEdge('a', 'b', 4)
G.addEdge('a', 'c', 1)
G.addEdge('c', 'b', 2)
G.addEdge('b', 'e', 4)
G.addEdge('c', 'd', 4)
G.addEdge('d', 'e', 4)
for v in G:
for w in v.getConnections():
vid = v.getVertexID()
wid = w.getVertexID()
print('( %s , %s, %3d)' % (vid, wid, v.getWeight(w)))
start = G.getVertex('a')
destination = G.getVertex('e')
dijkstra(G, start, destination)
# 起始点start 到 各个节点的距离
for v in G.vertexDict.values():
print(start.getVertexID(), " to ", v.getVertexID(), "-->", v.getDistance())
path = []
shortest(destination, path)
path = path + [start.getVertexID()]
print('The shortest path from a to e is: %s' % (path[::-1]))