算法描述
给出一个起始点,求出到达其他所有点的最短路径。以下图为例:假设v1为源点,找从v1到其它节点的最短路径。
结果:
v1到各节点的路径及其最短距离
v2:v1——v6——v2 = 5
v3:v1——v6——v2——v3 = 12
v4:v1——v6——v4 = 9
v5:v1——v6——v5 = 4
v6:v1——v6 = 3
算法实现
class Dijkstra:
"""
单源最短路径,边权重非负
"""
def dijkstra1(self, src: Node):
"""
:param src:
:return: 从src出发 到所有点的最短距离
"""
# key:从src出发到达的节点;value:从src出发到达的节点的最短距离,
# 若没有节点的记录,认为是正无穷
distanceMap = dict()
distanceMap[src] = 0
selectedNodes = set()
minNode = self.getMinDistanceAndUnselectedNode(distanceMap, selectedNodes)
while minNode:
distance = distanceMap.get(minNode)
for edge in minNode.edges:
dstNode = edge.dst
if dstNode not in distanceMap.keys():
distanceMap[dstNode] = distance + edge.weight
else:
distanceMap[edge.dst] = min(distanceMap.get(dstNode), distance + edge.weight)
selectedNodes.add(minNode)
minNode = self.getMinDistanceAndUnselectedNode(distanceMap, selectedNodes)
return distanceMap
def getMinDistanceAndUnselectedNode(self, distanceMap, touchNodes):
minNode = None
minDistance = float('inf')
for node, distance in distanceMap.items():
if node not in touchNodes and distance < minDistance:
minNode = node
minDistance = distance
return minNode
改进算法【小根堆】
class Dijkstra:
"""
单源最短路径,边权重非负
"""
class NodeRecord:
def __init__(self, node: Node, distance: int):
self.node = node
self.distance = distance
class NodeHeap:
def __init__(self, size: int):
# 实际的堆结构
self.nodes = [] * size
# key 某一个node, value 上面堆中的位置
self.heapIndexMap = dict()
# key 某一个节点, value 从源节点出发到该节点的目前最小距离
self.distanceMap = dict()
# 堆上有多少个点
self.size = 0
def isEmpty(self):
return self.size == 0
def addOrUpdateOrIgnore(self, node: Node, distance: int):
"""
有一个点叫node,现在发现了一个从源节点出发到达node的距离为distance
判断要不要更新,如果需要的话,就更新
:param node:
:param distance:
:return:
"""
if self.inHeap(node):
self.distanceMap[node] = min(self.distanceMap.get(node), distance)
self.insertHeapify(node, self.heapIndexMap.get(node))
if not self.isEntered(node):
self.nodes[self.size] = node
self.heapIndexMap[node] = self.size
self.distanceMap[node] = distance
self.insertHeapify(node, self.size)
self.size += 1
def isEntered(self, node: Node):
return self.heapIndexMap.__contains__(node)
def inHeap(self, node: Node):
return self.isEntered(node) and self.heapIndexMap.get(node) != -1
def insertHeapify(self, node: Node, index: int):
while self.distanceMap.get(self.nodes[index]) < self.distanceMap.get(self.nodes[(index-1)//2]):
self.swap(index, (index-1)//2)
index = (index-1)//2
def heapify(self, index: int, size: int):
left = index * 2 + 1
while left < size:
if left + 1 < size and self.distanceMap.get(self.nodes[left+1]) < self.distanceMap.get(self.nodes[left]):
smallest = left+1
else:
smallest = left
smallest = smallest if self.distanceMap.get(self.nodes[smallest]) < self.distanceMap.get(self.nodes[index]) else index
self.swap(smallest, index)
index = smallest
left = index * 2 + 1
def swap(self, index1: int, index2: int):
self.heapIndexMap[self.nodes[index1]] = index2
self.heapIndexMap[self.nodes[index2]] = index1
self.nodes[index1], self.nodes[index2] = self.nodes[index2], self.nodes[index1]
def pop(self):
nodeRecord = Dijkstra.NodeRecord(self.nodes[0], self.distanceMap.get(self.nodes[0]))
self.swap(0, self.size - 1)
self.heapIndexMap[self.nodes[self.size-1]] = -1
self.distanceMap.pop(self.nodes[self.size-1])
self.nodes[self.size-1] = None
self.heapify(0, self.size-1)
self.size -= 1
return nodeRecord
def dijkstra2(self, src: Node):
"""
改写堆
:param src:
:return:
"""
nodeHeap = Dijkstra.NodeHeap()
nodeHeap.addOrUpdateOrIgnore(src, 0)
result = dict()
while nodeHeap:
record = nodeHeap.pop()
cur = record.node
distance = record.distance
for edge in cur.edges:
nodeHeap.addOrUpdateOrIgnore(edge.dst, edge.weight+distance)
result[cur] = distance
return result