基于wiki上的代码修改实现,增加了解释部分,注意这部分中的解释并不是注重于解释算法本身,而是在进行对于由Pseudocode到真正具体语言实现时,需要进行的调整和变化,
本文预计列举Python实现和C++实现,在两种实现中对比揣摩,找到算法本质中相同的内核,同时也找到一些细节之处,两者不同的地方。从而进一步掌握由Pseudocode到真正可以运行的具体的计算机程式的相关技术。
from collections import namedtuple
from pprint import pprint as pp
inf = float('inf')
Edge = namedtuple('Edge', 'start, end, cost')
class Graph():
def __init__(self, edges):
self.edges = edges2 = [Edge(*edge) for edge in edges]
self.vertices = set(sum(([e.start, e.end] for e in edges2), []))
def dijkstra(self, source, dest):
assert source in self.vertices
dist = {vertex: inf for vertex in self.vertices}
previous = {vertex: None for vertex in self.vertices}
dist[source] = 0
q = self.vertices.copy()
neighbours = {vertex: set() for vertex in self.vertices}
for start, end, cost in self.edges:
neighbours[start].add((end, cost))
#pp(neighbours)
while q:
u = min(q, key=lambda vertex: dist[vertex])
q.remove(u)
if dist[u] == inf or u == dest:
break
for v, cost in neighbours[u]:
alt = dist[u] + cost
if alt < dist[v]: # Relax (u,v,a)
dist[v] = alt
previous[v] = u
#pp(previous)
s, u = [], dest
while previous[u]:
s.insert(0, u)
u = previous[u]
s.insert(0, u)
return s
graph = Graph([("a", "b", 7), ("a", "c", 9), ("a", "f", 14), ("b", "c", 10),
("b", "d", 15), ("c", "d", 11), ("c", "f", 2), ("d", "e", 6),
("e", "f", 9)])
pp(graph.dijkstra("a", "e"))
第一行中的 from collections import namedtuple,
其中namedtuple 可以视为tuple来使用,但是又有些不同之处。以下是查看文档获取的信息
namedtuple(typename, field_names, verbose=False, rename=False)
“”“
Returns a new subclass of tuple with named fields.
”“”
>>> Point = namedtuple('Point', ['x', 'y'])
>>> Point.__doc__ # docstring for the new class
'Point(x, y)'
>>> p = Point(11, y=22) # instantiate with positional args or keywords
>>> p[0] + p[1] # indexable like a plain tuple
33
>>> x, y = p # unpack like a regular tuple
>>> x, y
(11, 22)
>>> p.x + p.y # fields also accessable by name
33
>>> d = p._asdict() # convert to a dictionary
>>> d['x']
11
>>> Point(**d) # convert from a dictionary
Point(x=11, y=22)
>>> p._replace(x=100) # _replace() is like str.replace() but targets named fields
Point(x=100, y=22)
第二行的pprint就像它的名字一样,Data pretty printer。为了拥有漂亮的格式输出。
其中第十一行可能看起来比较令人费解,那么现在来逐层分析一下这行code,
sum(...)
sum(sequence[, start]) -> value
Return the sum of a sequence of numbers (NOT strings) plus the value
of parameter 'start' (which defaults to 0). When the sequence is
empty, return start.
明白了sum的含义之后,那么后面的 "[ ]"我们就很容易理解它是用来做什么的了,相当于每一个保持不变,但是不能使用defaults,因为,defaults是int型的0,不能与list相加。后面放一个空的列表,将所有的相加,组成一个新的大列表。
试以两个例子来理解一下sum如何使用
>> sum([1,2,3,1])
7
>> sum(([1],[2],[3]),[])
[1, 2, 3]