迪克斯特拉';python中的s算法
我试图使用数组在python中实现Dijkstra的算法。这是我的实现迪克斯特拉';python中的s算法,python,algorithm,dijkstra,Python,Algorithm,Dijkstra,我试图使用数组在python中实现Dijkstra的算法。这是我的实现 def extract(Q, w): m=0 minimum=w[0] for i in range(len(w)): if w[i]<minimum: minimum=w[i] m=i return m, Q[m] def dijkstra(G, s, t='B'): Q=[s] p={s:None}
def extract(Q, w):
m=0
minimum=w[0]
for i in range(len(w)):
if w[i]<minimum:
minimum=w[i]
m=i
return m, Q[m]
def dijkstra(G, s, t='B'):
Q=[s]
p={s:None}
w=[0]
d={}
for i in G:
d[i]=float('inf')
Q.append(i)
w.append(d[i])
d[s]=0
S=[]
n=len(Q)
while Q:
u=extract(Q,w)[1]
S.append(u)
#w.remove(extract(Q, d, w)[0])
Q.remove(u)
for v in G[u]:
if d[v]>=d[u]+G[u][v]:
d[v]=d[u]+G[u][v]
p[v]=u
return d, p
B='B'
A='A'
D='D'
G='G'
E='E'
C='C'
F='F'
G={B:{A:5, D:1, G:2}, A:{B:5, D:3, E:12, F:5}, D:{B:1, G:1, E:1, A:3}, G:{B:2, D:1, C:2}, C:{G:2, E:1, F:16}, E:{A:12, D:1, C:1, F:2}, F:{A:5, E:2, C:16}}
print "Assuming the start vertex to be B:"
print "Shortest distances", dijkstra(G, B)[0]
print "Parents", dijkstra(G, B)[1]
然而,我得到的答案是:
Assuming the start vertex to be B:
Shortest distances {'A': 4, 'C': 4, 'B': 0, 'E': 2, 'D': 1, 'G': 2, 'F': 10}
Parents {'A': 'D', 'C': 'G', 'B': None, 'E': 'D', 'D': 'B', 'G': 'D', 'F': 'A'}.
对于节点F,程序给出了不正确的答案。有人能告诉我为什么吗?正如其他人所指出的,由于没有使用可理解的变量名,调试代码几乎是不可能的
import sys
import heapq
class Node:
def __init__(self, name):
self.name = name
self.visited = False
self.adjacenciesList = []
self.predecessor = None
self.mindistance = sys.maxsize
def __lt__(self, other):
return self.mindistance < other.mindistance
class Edge:
def __init__(self, weight, startvertex, endvertex):
self.weight = weight
self.startvertex = startvertex
self.endvertex = endvertex
def calculateshortestpath(vertexlist, startvertex):
q = []
startvertex.mindistance = 0
heapq.heappush(q, startvertex)
while q:
actualnode = heapq.heappop(q)
for edge in actualnode.adjacenciesList:
tempdist = edge.startvertex.mindistance + edge.weight
if tempdist < edge.endvertex.mindistance:
edge.endvertex.mindistance = tempdist
edge.endvertex.predecessor = edge.startvertex
heapq.heappush(q,edge.endvertex)
def getshortestpath(targetvertex):
print("The value of it's minimum distance is: ",targetvertex.mindistance)
node = targetvertex
while node:
print(node.name)
node = node.predecessor
node1 = Node("A");
node2 = Node("B");
node3 = Node("C");
node4 = Node("D");
node5 = Node("E");
node6 = Node("F");
node7 = Node("G");
node8 = Node("H");
edge1 = Edge(5,node1,node2);
edge2 = Edge(8,node1,node8);
edge3 = Edge(9,node1,node5);
edge4 = Edge(15,node2,node4);
edge5 = Edge(12,node2,node3);
edge6 = Edge(4,node2,node8);
edge7 = Edge(7,node8,node3);
edge8 = Edge(6,node8,node6);
edge9 = Edge(5,node5,node8);
edge10 = Edge(4,node5,node6);
edge11 = Edge(20,node5,node7);
edge12 = Edge(1,node6,node3);
edge13 = Edge(13,node6,node7);
edge14 = Edge(3,node3,node4);
edge15 = Edge(11,node3,node7);
edge16 = Edge(9,node4,node7);
node1.adjacenciesList.append(edge1);
node1.adjacenciesList.append(edge2);
node1.adjacenciesList.append(edge3);
node2.adjacenciesList.append(edge4);
node2.adjacenciesList.append(edge5);
node2.adjacenciesList.append(edge6);
node8.adjacenciesList.append(edge7);
node8.adjacenciesList.append(edge8);
node5.adjacenciesList.append(edge9);
node5.adjacenciesList.append(edge10);
node5.adjacenciesList.append(edge11);
node6.adjacenciesList.append(edge12);
node6.adjacenciesList.append(edge13);
node3.adjacenciesList.append(edge14);
node3.adjacenciesList.append(edge15);
node4.adjacenciesList.append(edge16);
vertexlist = (node1,node2,node3,node4,node5,node6,node7,node8)
calculateshortestpath(vertexlist,node1)
getshortestpath(node7)
在关于Dijkstra算法的wiki文章之后,我们可以按照以下思路(以及无数其他方式)实现它:
这段代码过于冗长,我希望通过比较您的代码和我的代码,您可能会发现一些差异
结果是:
{'E': 2, 'D': 1, 'G': 2, 'F': 4, 'A': 4, 'C': 3, 'B': 0}
这不是我的答案——我的教授比我的尝试更有效率。这是他的方法,显然是对重复性任务使用帮助函数
def dijkstra(graph, source):
vertices, edges = graph
dist = dict()
previous = dict()
for vertex in vertices:
dist[vertex] = float("inf")
previous[vertex] = None
dist[source] = 0
Q = set(vertices)
while len(Q) > 0:
u = minimum_distance(dist, Q)
print('Currently considering', u, 'with a distance of', dist[u])
Q.remove(u)
if dist[u] == float('inf'):
break
n = get_neighbours(graph, u)
for vertex in n:
alt = dist[u] + dist_between(graph, u, vertex)
if alt < dist[vertex]:
dist[vertex] = alt
previous[vertex] = u
return previous
def dijkstra(图表,来源):
顶点,边=图
dist=dict()
previous=dict()
对于顶点中的顶点:
距离[顶点]=浮点(“inf”)
上一个[顶点]=无
距离[源]=0
Q=集合(顶点)
当len(Q)>0时:
u=最小距离(距离,Q)
打印('当前考虑',u',距离',dist[u])
Q.删除(u)
如果dist[u]==float('inf'):
打破
n=获取邻域(图,u)
对于n中的顶点:
alt=dist[u]+dist_之间(图形、u、顶点)
如果alt<距离[顶点]:
距离[顶点]=高度
上一个[顶点]=u
返回上一个
给出一个图表
({'A','B','C','D'},{'A','B',5),('B','A',5),('B','C',10),('B','D',6),('C','D',2),('D','C',2)})
命令print(dijkstra(图形'A')
产生
当前正在考虑距离为0的
目前正在考虑距离为5的B
目前正在考虑距离为11的D
目前正在考虑距离为13的C
id est:
{'C':'D','D':'B','A':无,'B':'A'}=>按随机顺序排列
为了让新手更清楚,我用了一种更详细的形式:
def get_parent(pos):
return (pos + 1) // 2 - 1
def get_children(pos):
right = (pos + 1) * 2
left = right - 1
return left, right
def swap(array, a, b):
array[a], array[b] = array[b], array[a]
class Heap:
def __init__(self):
self._array = []
def peek(self):
return self._array[0] if self._array else None
def _get_smallest_child(self, parent):
return min([
it
for it in get_children(parent)
if it < len(self._array)
], key=lambda it: self._array[it], default=-1)
def _sift_down(self):
parent = 0
smallest = self._get_smallest_child(parent)
while smallest != -1 and self._array[smallest] < self._array[parent]:
swap(self._array, smallest, parent)
parent, smallest = smallest, self._get_smallest_child(smallest)
def pop(self):
if not self._array:
return None
swap(self._array, 0, len(self._array) - 1)
node = self._array.pop()
self._sift_down()
return node
def _sift_up(self):
index = len(self._array) - 1
parent = get_parent(index)
while parent != -1 and self._array[index] < self._array[parent]:
swap(self._array, index, parent)
index, parent = parent, get_parent(parent)
def add(self, item):
self._array.append(item)
self._sift_up()
def __bool__(self):
return bool(self._array)
def backtrack(best_parents, start, end):
if end not in best_parents:
return None
cursor = end
path = [cursor]
while cursor in best_parents:
cursor = best_parents[cursor]
path.append(cursor)
if cursor == start:
return list(reversed(path))
return None
def dijkstra(weighted_graph, start, end):
"""
Calculate the shortest path for a directed weighted graph.
Node can be virtually any hashable datatype.
:param start: starting node
:param end: ending node
:param weighted_graph: {"node1": {"node2": weight, ...}, ...}
:return: ["START", ... nodes between ..., "END"] or None, if there is no
path
"""
distances = {i: float("inf") for i in weighted_graph}
best_parents = {i: None for i in weighted_graph}
to_visit = Heap()
to_visit.add((0, start))
distances[start] = 0
visited = set()
while to_visit:
src_distance, source = to_visit.pop()
if src_distance > distances[source]:
continue
if source == end:
break
visited.add(source)
for target, distance in weighted_graph[source].items():
if target in visited:
continue
new_dist = distances[source] + weighted_graph[source][target]
if distances[target] > new_dist:
distances[target] = new_dist
best_parents[target] = source
to_visit.add((new_dist, target))
return backtrack(best_parents, start, end)
def get_父项(pos):
返回(位置+1)//2-1
def get_儿童(pos):
右=(位置+1)*2
左=右-1
向左、向右返回
def交换(阵列、a、b):
数组[a],数组[b]=数组[b],数组[a]
类堆:
定义初始化(自):
self.\u数组=[]
def peek(自):
返回self.\u数组[0]如果self.\u数组其他无
定义获取最小的子项(自身、父项):
返回最小值([
信息技术
在get_children(家长)中为其设置
如果它距离[源]:
持续
如果源==结束:
打破
已访问。添加(源)
对于目标,加权图[source]中的距离。项()
如果访问了目标:
持续
新距离=距离[源]+加权图[源][目标]
如果距离[目标]>新距离:
距离[目标]=新距离
最佳父母[目标]=来源
添加((新地区,目标))
返回回溯(最佳父母,开始,结束)
在extract中设置一个断点。您将看到您从Q中删除了条目,但从未从w中删除。其他所有内容都是dict,但Q/w是一个配对数组,您无法保持最新。您必须保持这两个数组的同步,或用dict替换它们。特别注意:最后,在算法运行后,您可能希望用li替换Q/wst的边缘和重新编码的“提取”功能与优先队列(heapq模块)
此外,您将看到,对于源,w的权重始终为0,对于所有其他节点,w的权重始终为“inf”。您完全跳过了更新候选距离的关键步骤
因此,您基本上总是选择遇到的第一条路径,而不是选择最短路径
def get_parent(pos):
return (pos + 1) // 2 - 1
def get_children(pos):
right = (pos + 1) * 2
left = right - 1
return left, right
def swap(array, a, b):
array[a], array[b] = array[b], array[a]
class Heap:
def __init__(self):
self._array = []
def peek(self):
return self._array[0] if self._array else None
def _get_smallest_child(self, parent):
return min([
it
for it in get_children(parent)
if it < len(self._array)
], key=lambda it: self._array[it], default=-1)
def _sift_down(self):
parent = 0
smallest = self._get_smallest_child(parent)
while smallest != -1 and self._array[smallest] < self._array[parent]:
swap(self._array, smallest, parent)
parent, smallest = smallest, self._get_smallest_child(smallest)
def pop(self):
if not self._array:
return None
swap(self._array, 0, len(self._array) - 1)
node = self._array.pop()
self._sift_down()
return node
def _sift_up(self):
index = len(self._array) - 1
parent = get_parent(index)
while parent != -1 and self._array[index] < self._array[parent]:
swap(self._array, index, parent)
index, parent = parent, get_parent(parent)
def add(self, item):
self._array.append(item)
self._sift_up()
def __bool__(self):
return bool(self._array)
def backtrack(best_parents, start, end):
if end not in best_parents:
return None
cursor = end
path = [cursor]
while cursor in best_parents:
cursor = best_parents[cursor]
path.append(cursor)
if cursor == start:
return list(reversed(path))
return None
def dijkstra(weighted_graph, start, end):
"""
Calculate the shortest path for a directed weighted graph.
Node can be virtually any hashable datatype.
:param start: starting node
:param end: ending node
:param weighted_graph: {"node1": {"node2": weight, ...}, ...}
:return: ["START", ... nodes between ..., "END"] or None, if there is no
path
"""
distances = {i: float("inf") for i in weighted_graph}
best_parents = {i: None for i in weighted_graph}
to_visit = Heap()
to_visit.add((0, start))
distances[start] = 0
visited = set()
while to_visit:
src_distance, source = to_visit.pop()
if src_distance > distances[source]:
continue
if source == end:
break
visited.add(source)
for target, distance in weighted_graph[source].items():
if target in visited:
continue
new_dist = distances[source] + weighted_graph[source][target]
if distances[target] > new_dist:
distances[target] = new_dist
best_parents[target] = source
to_visit.add((new_dist, target))
return backtrack(best_parents, start, end)
import sys
import heapq
class Node:
def __init__(self, name):
self.name = name
self.visited = False
self.adjacenciesList = []
self.predecessor = None
self.mindistance = sys.maxsize
def __lt__(self, other):
return self.mindistance < other.mindistance
class Edge:
def __init__(self, weight, startvertex, endvertex):
self.weight = weight
self.startvertex = startvertex
self.endvertex = endvertex
def calculateshortestpath(vertexlist, startvertex):
q = []
startvertex.mindistance = 0
heapq.heappush(q, startvertex)
while q:
actualnode = heapq.heappop(q)
for edge in actualnode.adjacenciesList:
tempdist = edge.startvertex.mindistance + edge.weight
if tempdist < edge.endvertex.mindistance:
edge.endvertex.mindistance = tempdist
edge.endvertex.predecessor = edge.startvertex
heapq.heappush(q,edge.endvertex)
def getshortestpath(targetvertex):
print("The value of it's minimum distance is: ",targetvertex.mindistance)
node = targetvertex
while node:
print(node.name)
node = node.predecessor
node1 = Node("A");
node2 = Node("B");
node3 = Node("C");
node4 = Node("D");
node5 = Node("E");
node6 = Node("F");
node7 = Node("G");
node8 = Node("H");
edge1 = Edge(5,node1,node2);
edge2 = Edge(8,node1,node8);
edge3 = Edge(9,node1,node5);
edge4 = Edge(15,node2,node4);
edge5 = Edge(12,node2,node3);
edge6 = Edge(4,node2,node8);
edge7 = Edge(7,node8,node3);
edge8 = Edge(6,node8,node6);
edge9 = Edge(5,node5,node8);
edge10 = Edge(4,node5,node6);
edge11 = Edge(20,node5,node7);
edge12 = Edge(1,node6,node3);
edge13 = Edge(13,node6,node7);
edge14 = Edge(3,node3,node4);
edge15 = Edge(11,node3,node7);
edge16 = Edge(9,node4,node7);
node1.adjacenciesList.append(edge1);
node1.adjacenciesList.append(edge2);
node1.adjacenciesList.append(edge3);
node2.adjacenciesList.append(edge4);
node2.adjacenciesList.append(edge5);
node2.adjacenciesList.append(edge6);
node8.adjacenciesList.append(edge7);
node8.adjacenciesList.append(edge8);
node5.adjacenciesList.append(edge9);
node5.adjacenciesList.append(edge10);
node5.adjacenciesList.append(edge11);
node6.adjacenciesList.append(edge12);
node6.adjacenciesList.append(edge13);
node3.adjacenciesList.append(edge14);
node3.adjacenciesList.append(edge15);
node4.adjacenciesList.append(edge16);
vertexlist = (node1,node2,node3,node4,node5,node6,node7,node8)
calculateshortestpath(vertexlist,node1)
getshortestpath(node7)
import heapq as hq
import math
def dijkstra(G, s):
n = len(G)
visited = [False]*n
weights = [math.inf]*n
path = [None]*n
queue = []
weights[s] = 0
hq.heappush(queue, (0, s))
while len(queue) > 0:
g, u = hq.heappop(queue)
visited[u] = True
for v, w in G[u]:
if not visited[v]:
f = g + w
if f < weights[v]:
weights[v] = f
path[v] = u
hq.heappush(queue, (f, v))
return path, weights
G = [[(1, 6), (3, 7)],
[(2, 5), (3, 8), (4, -4)],
[(1, -2), (4, 7)],
[(2, -3), (4, 9)],
[(0, 2)]]
print(dijkstra(G, 0))
import sys
def shortestpath(graph,start,end,visited=[],distances={},predecessors={}):
"""Find the shortest path btw start & end nodes in a graph"""
# detect if first time through, set current distance to zero
if not visited: distances[start]=0
# if we've found our end node, find the path to it, and return
if start==end:
path=[]
while end != None:
path.append(end)
end=predecessors.get(end,None)
return distances[start], path[::-1]
# process neighbors as per algorithm, keep track of predecessors
for neighbor in graph[start]:
if neighbor not in visited:
neighbordist = distances.get(neighbor,sys.maxint)
tentativedist = distances[start] + graph[start][neighbor]
if tentativedist < neighbordist:
distances[neighbor] = tentativedist
predecessors[neighbor]=start
# neighbors processed, now mark the current node as visited
visited.append(start)
# finds the closest unvisited node to the start
unvisiteds = dict((k, distances.get(k,sys.maxint)) for k in graph if k not in visited)
closestnode = min(unvisiteds, key=unvisiteds.get)
# now take the closest node and recurse, making it current
return shortestpath(graph,closestnode,end,visited,distances,predecessors)
if __name__ == "__main__":
graph = {'a': {'w': 14, 'x': 7, 'y': 9},
'b': {'w': 9, 'z': 6},
'w': {'a': 14, 'b': 9, 'y': 2},
'x': {'a': 7, 'y': 10, 'z': 15},
'y': {'a': 9, 'w': 2, 'x': 10, 'z': 11},
'z': {'b': 6, 'x': 15, 'y': 11}}
print shortestpath(graph,'a','a')
print shortestpath(graph,'a','b')
"""
Expected Result:
(0, ['a'])
(20, ['a', 'y', 'w', 'b'])
"""
import heapq
def dijkstra(g, s, t):
q = []
d = {k: sys.maxint for k in g.keys()}
p = {}
d[s] = 0
heapq.heappush(q, (0, s))
while q:
last_w, curr_v = heapq.heappop(q)
for n, n_w in g[curr_v]:
cand_w = last_w + n_w # equivalent to d[curr_v] + n_w
# print d # uncomment to see how deltas are updated
if cand_w < d[n]:
d[n] = cand_w
p[n] = curr_v
heapq.heappush(q, (cand_w, n))
print "predecessors: ", p
print "delta: ", d
return d[t]
def test():
og = {}
og["s"] = [("t", 10), ("y", 5)]
og["t"] = [("y", 2), ("x", 1)]
og["y"] = [("t", 3), ("x", 9), ("z", 2)]
og["z"] = [("x", 6), ("s", 7)]
og["x"] = [("z", 4)]
assert dijkstra(og, "s", "x") == 9
if __name__ == "__main__":
test()
Distance from B to C is: 3.00
Path from B to C is: B -> D -> E -> C