Prim和Dijkstra居然写起来一模一样

本文深入探讨Prim和Dijkstra算法的相似性和差异,通过代码对比揭示两者在解决图问题时的不同策略,即Prim算法专注于构建最小生成树,而Dijkstra算法侧重于寻找最短路径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一句话概括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

从起点VertexstartVertex_{start}Vertexstart,到距离这个点最远的点VertexendVertex_{end}Vertexend, 之间的路径我们暂且叫PATHPATHPATH
Dijkstra实际上是在找这个PATHPATHPATH的最小值,不止最远的点找了,其他点也都找了;
Prim一直再找最近的点,也就是边最短的点,直到找了n-1条边,实际上是在约束条件下(不成环)找走过边和最短的PATHPATHPATH实际上最短PATHPATHPATH也是不可能有环的,加入有环肯定是绕路了(从这里可以看得出算法的基础是数学,好的算法和数学关系很大);
Dijkstra实际上是在找最远点PATHPATHPATH的最小值,等价于,从起始点,约束条件下不断加最短边,直到加n-1条边。
也就是他们在解决同一个问题。

但是这个还是没有反映出他们的代码为何一模一样,简直是兄弟?

1、图类问题的遍历都是借助于邻居辐射,一传十,十传百,根本就不怕扩算乱了,因为已经做了标记处理了,所以框架都差不多;
2、都是基于贪心的处理,用了堆数据结构,基于的标准不一样(这个不一样成了他们的唯一不一样了);
3、为了记录路径,都用到(parent,node, weight),这也是路径的一般处理方式;
4、他们算法都太简单了(懂了的情况下),没几行,所以就没啥差异了啊。

### 主要差异 Prim算法Dijkstra算法虽然都采用了贪心策略,但在具体的应用场景以及实现细节上存在显著的不同。 #### 贪心策略的选择标准 Prim算法选择从未访问节点集合中挑选距离当前最小生成树(MST)最近的一个顶点加入到MST中[^4]。而Dijkstra算法则是从未访问过的节点里选出离起点最短路径长度最小的那个作为下一个处理对象。 #### 应用场景 - **Prim算法** - 适用于求解无向连通加权图中的最小生成树问题。 - 当目标是从给定网络构建一棵连接所有顶点且总权重最低的树时使用此方法[^1]。 - **Dijkstra算法** - 针对单源最短路径问题设计,在有向或无向带非负边权的图中寻找从指定起始点出发到达其他各点间的最短路徑[^2]。 - 如果需求是在一张地图上找到由某城市至其余城市的最快路线,则应采用该算法[^3]。 ```python # Python 实现 Prim 算法获取 MST 的部分伪代码 def prim(graph, start_vertex): mst_set = set([start_vertex]) edges = [] while len(mst_set) != len(graph.vertices()): min_edge = None for vertex in mst_set: for neighbor, weight in graph[vertex].items(): if neighbor not in mst_set and (min_edge is None or weight < min_edge[2]): min_edge = (vertex, neighbor, weight) if min_edge: edges.append(min_edge) mst_set.add(min_edge[1]) return edges # Python 实现 Dijkstra 算法的部分伪代码 import heapq def dijkstra(graph, source): queue = [(0, source)] distances = {source: 0} visited = [] while queue: dist, current_node = heapq.heappop(queue) if current_node in visited: continue visited.append(current_node) for neighbour, cost in graph[current_node]: old_cost = distances.get(neighbour, float('inf')) new_cost = dist + cost if new_cost < old_cost: distances[neighbour] = new_cost heapq.heappush(queue, (new_cost, neighbour)) return distances ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值