@@ -128,54 +128,61 @@ for i in range(1, n + 1):
128128### 3.2 堆优化 Dijkstra 算法实现步骤
129129
1301301 . 初始化距离数组,源点距离设为 $0$,其余节点设为无穷大。
131- 2 . 创建优先队列,将 $(0, source)$ 入队。
131+ 2 . 创建优先队列,将源节点及其距离 $(0, source)$ 入队。
1321323 . 当优先队列非空时,重复以下操作:
133133 - 弹出队首(距离最小)节点;
134- - 若该节点的距离已大于当前最短距离 ,跳过;
134+ - 如果该节点的距离已大于当前最短距离 ,跳过;
135135 - 否则,遍历其所有邻居,尝试松弛:
136- - 若通过当前节点到邻居的距离更短 ,则更新距离并将新距离入队。
136+ - 如果通过当前节点到邻居的距离更短 ,则更新距离并将新距离入队。
1371374 . 队列为空时结束,返回所有节点的最短距离数组。
138138
139- ### 3.3 堆优化的 Dijkstra 算法实现代码
139+ ### 3.3 堆优化 Dijkstra 算法实现代码
140140
141141``` python
142142import heapq
143143
144144class Solution :
145145 def dijkstra (self , graph , n , source ):
146- # 初始化距离数组
147- dist = [float (' inf' ) for _ in range (n + 1 )]
148- dist[source] = 0
149-
150- # 创建优先队列,存储 (距离, 节点) 的元组
146+ """
147+ 堆优化 Dijkstra 算法,计算单源最短路径
148+ :param graph: 邻接表,graph[u] = {v: w, ...}
149+ :param n: 节点总数(节点编号从 1 到 n)
150+ :param source: 源点编号
151+ :return: dist[i] 表示源点到 i 的最短距离
152+ """
153+ # 距离数组,初始化为无穷大
154+ dist = [float (' inf' )] * (n + 1 )
155+ dist[source] = 0 # 源点到自身距离为 0
156+
157+ # 小根堆,存储 (距离, 节点) 元组
151158 priority_queue = [(0 , source)]
152-
159+
153160 while priority_queue:
154161 current_distance, current_node = heapq.heappop(priority_queue)
155-
156- # 如果当前距离大于已知的最短距离,跳过
162+ # 如果弹出的节点距离不是最短的,说明已被更新,跳过
157163 if current_distance > dist[current_node]:
158164 continue
159-
160- # 遍历当前节点的所有相邻节点
161- for neighbor, weight in graph[current_node].items():
162- distance = current_distance + weight
163- if distance < dist[neighbor]:
164- dist[neighbor] = distance
165- heapq.heappush(priority_queue, (distance, neighbor))
166-
165+
166+ # 遍历当前节点的所有邻居
167+ for neighbor, weight in graph.get(current_node, {}).items():
168+ new_distance = current_distance + weight
169+ # 如果找到更短路径,则更新并入堆
170+ if new_distance < dist[neighbor]:
171+ dist[neighbor] = new_distance
172+ heapq.heappush(priority_queue, (new_distance, neighbor))
173+
167174 return dist
168175
169176# 使用示例
170- # 创建一个有向图,使用邻接表表示
177+ # 构建一个有向图,邻接表表示
171178graph = {
172179 1 : {2 : 2 , 3 : 4 },
173180 2 : {3 : 1 , 4 : 7 },
174181 3 : {4 : 3 },
175182 4 : {}
176183}
177- n = 4 # 图中节点数量
178- source = 1 # 源节点
184+ n = 4 # 节点数量
185+ source = 1 # 源点编号
179186
180187dist = Solution().dijkstra(graph, n, source)
181188print (" 从节点" , source, " 到其他节点的最短距离:" )
@@ -186,27 +193,15 @@ for i in range(1, n + 1):
186193 print (f " 到节点 { i} 的距离: { dist[i]} " )
187194```
188195
189- 代码解释:
190-
191- 1 . ` graph ` 是一个字典,表示图的邻接表。例如,` graph[1] = {2: 3, 3: 4} ` 表示从节点 1 到节点 2 的边权重为 3,到节点 3 的边权重为 4。
192- 2 . ` n ` 是图中顶点的数量。
193- 3 . ` source ` 是源节点的编号。
194- 4 . ` dist ` 数组存储源点到各个节点的最短距离。
195- 5 . ` priority_queue ` 是一个优先队列,用来选择当前距离源点最近的节点。队列中的元素是 (距离, 节点) 的元组。
196- 6 . 主循环中,每次从队列中取出距离最小的节点。如果该节点的距离已经被更新过,跳过。
197- 7 . 对于当前节点的每一个邻居,计算通过当前节点到达邻居的距离。如果这个距离比已知的更短,更新距离并将邻居加入队列。
198- 8 . 最终,` dist ` 数组中存储的就是源点到所有节点的最短距离。
199-
200- ### 3.4 堆优化的 Dijkstra 算法复杂度分析
196+ ### 3.4 堆优化 Dijkstra 算法复杂度分析
201197
202- - ** 时间复杂度** :$O((V + E) \log V)$
203- - 每个节点最多被加入优先队列一次,每次操作的时间复杂度为 $O(\log V)$
204- - 每条边最多被处理一次,每次处理的时间复杂度为 $O(\log V)$
205- - 因此总时间复杂度为 $O((V + E) \log V)$
198+ - ** 时间复杂度** :$O((V + E) \log V)$。
199+ - 堆优化 Dijkstra 算法中,每个节点最多会被弹出优先队列一次,每次弹出操作的复杂度为 $O(\log V)$。
200+ - 每条边在松弛操作时最多会导致一次入堆,入堆操作的复杂度同样为 $O(\log V)$。
201+ - 因此,总体时间复杂度为 $O((V + E) \log V)$,其中 $V$ 为节点数,$E$ 为边数。
206202
207- - ** 空间复杂度** :$O(V)$
208- - 需要存储距离数组,大小为 $O(V)$。
209- - 优先队列在最坏情况下可能存储所有节点,大小为 $O(V)$。
203+ - ** 空间复杂度** :$O(V)$。
204+ - 主要空间消耗在距离数组和优先队列,二者最坏情况下均为 $O(V)$ 级别。
210205
211206## 练习题目
212207
0 commit comments