dijkstra算法(单源最短路径) python实现

本文深入讲解了Dijkstra算法的两种实现方式,一种是最原始的方法,时间复杂度为O(n^2),另一种是通过队列优化后的版本。文章提供了详细的代码示例,并构建了一个邻接表来演示算法的运行过程。

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

用例图:
在这里插入图片描述
代码1:
用最原始的方式实现dijkstra,就是每次从costs里面找最短路径的点,再遍历这个点的边,更新最短路径。由于每次都要从costs里面找最短路径,时间复杂读为O(n^2)。

# dijjkstra算法(原生最短路径,还未优化)
def dij(start, graph):
    n = len(graph)
    # 初始化各项数据,把costs[start]初始化为0,其他为无穷大
    # 把各个顶点的父结点设置成-1
    costs = [99999 for _ in range(n)]
    costs[start] = 0
    parents = [-1 for _ in range(n)]
    visited = [False for _ in range(n)] # 标记已确定好最短花销的点
    t = []  # 已经确定好最短花销的点列表
    while len(t) < n:
        # 从costs里面找最短花销(找还没确定的点的路径),标记这个最短边的顶点,把顶点加入t中
        minCost = 99999
        minNode = None
        for i in range(n):
            if not visited[i] and costs[i] < minCost:
                minCost = costs[i]
                minNode = i
        t.append(minNode)
        visited[minNode] = True

        # 从这个顶点出发,遍历与它相邻的顶点的边,计算最短路径,更新costs和parents
        for edge in graph[minNode]:
            if not visited[edge[0]] and minCost + edge[1] < costs[edge[0]]:
                costs[edge[0]] = minCost + edge[1]
                parents[edge[0]] = minNode
    return costs, parents


# 主程序

# Data
data = [
    [1, 0, 8],
    [1, 2, 5],
    [1, 3, 10],
    [1, 6, 9],
    [2, 0, 1],
    [0, 6, 2],
    [3, 6, 5],
    [3, 4, 8],
    [0, 5, 4],
    [5, 6, 7],
    [5, 3, 8],
    [5, 4, 5]
]
n = 7  # 结点数

# 用data数据构建邻接表
graph = [[] for _ in range(n)]
for edge in data:
    graph[edge[0]].append([edge[1], edge[2]])
    graph[edge[1]].append([edge[0], edge[2]])
# for edges in graph:
#     print(edges)

# 从1开始找各点到1的最短路径(单源最短路径)
# costs: 各点到店1的最短路径
# parents: 各点链接的父结点,可以用parents建立最短路径生成树
costs, parents = dij(1, graph)
print('costs')
print(costs)
print('parents')
print(parents)

# 结果:
# costs
# [6, 0, 5, 10, 15, 10, 8]
# parents
# [2, -1, 1, 1, 5, 0, 0]

代码2:用队列优化过的dijk,函数可以直接套用上面的测试代码测试

# 用优先队列实现的dijkstra算法
def dij_pq(start, graph):
    n = len(graph)
    pq = pQueue()  # 队列中的元素为[cost, v]形式,cost是该路径的花销, v是去往的结点
    visited = [False for _ in range(n)]
    t = {}
    parents = [-1 for _ in range(n)]
    pq.put([0, start, -1])
    while len(t) < n:
        # 从优先队列中找出未被确定的最短路径
        minPath = pq.get()
        while visited[minPath[1]]:
            minPath = pq.get()

        minNode = minPath[1]
        visited[minNode] = True
        t[minNode] = minPath[0]
        parents[minNode] = minPath[2]

        # 从该最短路径的结点开始找邻边,入队
        for edge in graph[minNode]:
            if not visited[edge[0]]:
                pq.put([edge[1] + t[minNode], edge[0], minNode])
    return t, parents
### 回答1: 当然可以,以下是Dijkstra算法Python代码: ```python import heapq def dijkstra(graph, start): # 初始化距离和前驱字典 distances = {vertex: float('inf') for vertex in graph} distances[start] = 0 previous_vertices = {vertex: None for vertex in graph} # 初始化堆 vertices = [(0, start)] heapq.heapify(vertices) while vertices: # 取出堆中最小距离的节点 current_distance, current_vertex = heapq.heappop(vertices) # 如果当前距离已经大于记录的距离,则直接跳过 if current_distance > distances[current_vertex]: continue # 遍历当前节点的所有邻居 for neighbor, weight in graph[current_vertex].items(): distance = current_distance + weight # 如果新距离比记录距离小,则更新 if distance < distances[neighbor]: distances[neighbor] = distance previous_vertices[neighbor] = current_vertex heapq.heappush(vertices, (distance, neighbor)) return distances, previous_vertices ``` 以上代码实现Dijkstra算法,接受一个邻接字典表示的图和一个起始节点,返回一个距离字典和前驱字典。其中,邻接字典中每个键值对表示一个节点和它的所有邻居及边权重。 ### 回答2: Dijkstra算法(又称为迪杰斯特拉算法、戴克斯特拉算法)是一种用于计算图中最短路径的贪心算法,广泛应用于路由算法或作为其他图算法的子模块。Dijkstra算法本质上是一种贪心算法,每次找到到某个节点最短路径上的下一个节点,并标记出该节点到起点的距离,推广到整个图上就得到了从起点到各个节点的最短路径。 下面给出Dijkstra算法Python代码实现: ``` import heapq def dijkstra(graph, start): distances = {vertex: 0 if vertex == start else float('inf') for vertex in graph} heap = [(0, start)] while heap: current_distance, current_vertex = heapq.heappop(heap) if current_distance > distances[current_vertex]: continue for neighbor, weight in graph[current_vertex].items(): distance = current_distance + weight if distance < distances[neighbor]: distances[neighbor] = distance heapq.heappush(heap, (distance, neighbor)) return distances ``` 这个算法首先初始化了每个节点到起点的距离,然后将起点加入堆中,堆中存放的是当前最短路径节点和对应的距离。然后每次从堆中取出堆顶元素,如果堆顶元素的距离已经大于当前最短距离,则跳过该节点。如果堆顶元素的距离小于当前最短距离,则更新该节点到起点的距离,并将它的邻居节点加入堆中。 这个实现中使用了一个优先队列来维护最短距离的节点,这使得算法的时间复杂度从O(n^2)降低到了O(m log n),其中n是节点数,m是边数。 ### 回答3: Dijkstra算法是一种用于寻找带权有向图中单源最短路径算法。本文将为大家介绍如何用Python语言实现Dijkstra算法Dijkstra算法主要思路是通过贪心策略,先找到起点到每个顶点的最短路径,然后利用这些信息进一步缩小搜索范围,最终找到起点到目标点的最短路径。 以下是Dijkstra算法Python代码实现: ``` python #定义初始化函数,将各个点的距离和前一个节点都初始化为-1 def init(graph, start): d = {} p = {} for node in graph: d[node] = -1 p[node] = "" d[start] = 0 return d, p #定义算法函数。其中graph为图的数据表示(例如邻接矩阵或邻接表),start是起始节点 def dijkstra(graph, start): d, p = init(graph, start) unseen_nodes = list(graph.keys()) #未处理的节点集合 while len(unseen_nodes) > 0: #找到当前未处理节点中距离起点最短的节点 shortest = None node = "" for temp_node in unseen_nodes: if shortest == None: shortest = d[temp_node] node = temp_node elif d[temp_node] < shortest: shortest = d[temp_node] node = temp_node #遍历当前节点的所有出边,更新相邻节点的距离和前一个节点 for i, weight in graph[node].items(): if d[i] < 0 or d[i] > d[node] + weight: d[i] = d[node] + weight p[i] = node unseen_nodes.remove(node) return d, p #测试代码 graph = {0: {1: 1, 2: 4}, 1: {2: 2, 3: 5}, 2: {3: 1}, 3: {2: 1, 4: 3}, 4: {0: 3, 3: 1}} d, p = dijkstra(graph, 0) print(d) #{0: 0, 1: 1, 2: 3, 3: 4, 4: 3} print(p) #{0: '', 1: 0, 2: 1, 3: 2, 4: 3} ``` 在上述代码中,我们先定义了一个名为init的初始化函数,它接收一个表示图的数据结构和起点的参数,将所有顶点的距离和前一个节点初始化为-1,将起点的距离设置为0。接下来,我们定义了一个名为dijkstra算法函数,它接收一个表示图的数据结构和起点的参数,返回一个字典d表示起点到各个顶点的距离,另一个字典p表示与每个节点相邻的前一个节点。该算法首先调用初始化函数,将所有节点的距离和前一个节点初始化,然后遍历所有未处理的节点,在其中找到距离起点最短的节点,将其标记为已处理。然后遍历当前节点的所有出边,更新相邻节点的距离和前一个节点。这个过程重复进行,直到所有节点都被处理完。最后,算法返回d和p两个字典表示起点到各个节点的最短距离和前一个节点。 总结来说,Dijkstra算法是一种非常实用的最短路径算法,在实际应用中具有广泛的应用。Python语言中有许多实现算法,也可以通过简单的代码实现。掌握Dijkstra算法实现方法,对于提高编程的实战能力和解决实际问题有很大帮助。
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值