一句话概括Prim和Dijkstra:
Dijkstra:依次找距离起点从近到远的点;
Prim:从起点开始找距离最近的点,且不形成环。
这样表述还看不出来什么
我们先对比二者的代码:
def dijkstra2(graph,start):
vnum = len(graph)
pqueue = []
heapq.heappush(pqueue,(0.0,None,start))
paths = {vertex : None for vertex in graph}
count = 0
while count < vnum and pqueue:
pair = heapq.heappop(pqueue)
distance = pair[0]
parent = pair[1]
vertex = pair[2]
if paths[vertex]:
continue
paths[vertex] = (parent,distance)
edges = graph[vertex]
for v in edges:
if paths[v] is None:
heapq.heappush(pqueue,(distance + graph[vertex][v],vertex,v))
count += 1
return paths
#%%
def prim(graph,start):
vnum = len(graph)
pqueue = []
heapq.heappush(pqueue,(0.0,None,start))
mst = {vertex : None for vertex in graph}
count = 0
while count < vnum and pqueue:
pair = heapq.heappop(pqueue)
dist = pair[0]
parent = pair[1]
vertex = pair[2]
if mst[vertex]:
continue
mst[vertex]=(parent,dist)
edges = graph[vertex]
for v in edges:
if mst[v] is None:
heapq.heappush(pqueue,(graph[vertex][v],vertex,v))
count += 1
return mst
AMAZING,看到了没有,简直一模一样!!!!!
只不过压堆时,一个压的是边的距离,一个压的是到起点的距离。
所以我们还要继续思考:Prim和Dijkstra
从起点
,到距离这个点最远的点
, 之间的路径我们暂且叫
。
Dijkstra实际上是在找这个
的最小值,不止最远的点找了,其他点也都找了;
Prim一直再找最近的点,也就是边最短的点,直到找了n-1条边,实际上是在约束条件下(不成环)找走过边和最短的
,实际上最短
也是不可能有环的,加入有环肯定是绕路了(从这里可以看得出算法的基础是数学,好的算法和数学关系很大);
Dijkstra实际上是在找最远点
的最小值,等价于,从起始点,约束条件下不断加最短边,直到加n-1条边。
也就是他们在解决同一个问题。
但是这个还是没有反映出他们的代码为何一模一样,简直是兄弟?
1、图类问题的遍历都是借助于邻居辐射,一传十,十传百,根本就不怕扩算乱了,因为已经做了标记处理了,所以框架都差不多;
2、都是基于贪心的处理,用了堆数据结构,基于的标准不一样(这个不一样成了他们的唯一不一样了);
3、为了记录路径,都用到(parent,node, weight),这也是路径的一般处理方式;
4、他们算法都太简单了(懂了的情况下),没几行,所以就没啥差异了啊。