📚408数据结构|最短路径算法一篇彻底搞懂!BFS、Dijkstra、Floyd别再傻傻分不清了

考研408数据结构|最短路径|BFS|Dijkstra|Floyd

这几个算法真的太容易混了😭

尤其是看到"最短路径"四个字就开始纠结:

到底用BFS?Dijkstra?还是Floyd?

我把这几个算法按照**「能不能带权 → 求几对顶点 → 怎么写」**整理了一遍,考试直接按这个思路判断!

🧠 一、先记住:最短路径算法就这三个核心

408里最常见的最短路径算法:

算法 适用图 求什么
🚶 BFS 无权图 单源最短路径
🚗 Dijkstra 带权图,边权非负 单源最短路径
🌐 Floyd 带权/无权都可以 任意两点之间最短路径

一句话记忆👇

无权 → BFS

有权 → Dijkstra

所有点两两之间 → Floyd

⚠️ 注意一个特别容易考的点:

Dijkstra不能处理存在负权边的图!

🚶 二、BFS为什么可以求无权图最短路径?

因为BFS是一层一层往外扩展的。

假设从源点 0 出发:

0

/ \

1 2

/ \

3 4

BFS访问顺序大概就是:

0 → 1、2 → 3、4

也就是说:

  • 第0层:距离0
  • 第1层:距离1
  • 第2层:距离2
  • 第3层:距离3

所以:

BFS第一次访问到某个顶点时,得到的就是它距离源点的最短边数。

这就是为什么无权图求最短路径可以直接用BFS。

✍️ BFS求最短路径怎么写?

核心就是两个数组:

dist\[\]:记录源点到各顶点的最短距离

path\[\]:记录每个顶点是从谁走过来的

初始化:

disti = -1

pathi = -1

源点:

dists = 0

然后把源点加入队列。

BFS循环:

每次从队列中取出一个顶点 u:

遍历 u 的所有邻接点 v:

如果:

distv == -1

说明 v还没有被访问过。

那么:

distv = distu + 1

pathv = u

然后:

v入队

最后通过 path\[\] 就可以把最短路径倒推出来。

🚗 三、Dijkstra:带权图最短路径的王者

如果图变成这样:

2

0 ─────→ 1

│ │

5│ │1

↓ ↓

2 ─────→ 3

2

这时候就不能简单用BFS了。

因为:

边有不同的权值,走一步不代表距离只增加1。

这时候就轮到:

⭐ Dijkstra算法

它解决的是:

一个源点 → 其他所有顶点的最短路径

也就是:

单源最短路径。

📝 Dijkstra最重要的三个数组

和你笔记里整理的一样,可以重点记:

dist\[\]

path\[\]

final\[\]

① dist\[\]

记录:

源点到每个顶点当前已知的最短距离

例如:

dist3 = 7

表示目前知道:

源点 → 3 的最短距离是7。

② path\[\]

记录:

最短路径上,该顶点的前驱结点是谁

比如:

path3 = 2

说明:

...... → 2 → 3

所以最后可以利用 path\[\] 把完整路径还原出来。

③ final\[\]

这个非常重要‼️

finali = true

表示:

顶点i的最短距离已经最终确定。

也就是说,后面不会再修改它。

🔥 Dijkstra到底在干什么?

其实就一句话:

每次从"还没确定最短路的顶点"中,挑一个 dist 最小的出来,把它确定下来,然后利用它去更新其他顶点。

这个过程叫:

「选最小 + 松弛」

Dijkstra步骤直接背👇

① 初始化

disti = ∞

pathi = -1

finali = false

源点:

dists = 0

② 选择当前dist最小的顶点

从所有:

finali == false

的顶点中,

找到:

disti

最小的那个。

记作:

u

然后:

finalu = true

③ 用u更新其他顶点

遍历 u 的邻接点 v:

如果发现:

distu + arcuv < distv

那么更新:

distv = distu + arcuv

pathv = u

这一步就是传说中的:

「松弛操作」

④ 重复

重复:

选最小 → 确定 → 松弛

直到所有顶点都确定。

通常重复 n-1次 就可以得到最终结果。

🌐 四、Floyd:直接把"所有点到所有点"一次性算出来

如果题目问:

求任意两个顶点之间的最短路径

这时候Dijkstra就不够方便了。

因为Dijkstra是:

一个源点 → 所有点

如果你要:

1 → 2

1 → 3

1 → 4

2 → 1

2 → 3

2 → 4

......

那就要对每个顶点都跑一次Dijkstra。

这时候可以直接使用:

⭐ Floyd算法

🧠 Floyd的核心思想

Floyd特别适合用一句话理解:

尝试让某个顶点k作为中间点,看经过k是不是比原来的路更短。

例如原来:

i ─────────→ j

10

如果发现:

i → k = 3

k → j = 4

那么:

i → k → j = 3 + 4 = 7

比原来的10更短。

于是更新:

distij = 7

也就是:

distij

=

min(distij,

distik + distkj)

🔥 这就是Floyd最核心的公式!

📌 Floyd为什么是三个for循环?

因为它要依次考虑:

k = 0,1,2,...,n-1

作为中间点。

核心代码逻辑就是:

for k

for i

for j

distij =

min(distij,

distik + distkj)

所以时间复杂度:

⏱️ O(n³)

⚡ 五、三种算法到底怎么选?

这张表建议直接保存👇

题目条件 算法
无权图 + 一个源点 BFS
带权图 + 一个源点 Dijkstra
带权图 + 任意两点 Floyd
无权图 + 任意两点 Floyd也可以
存在负权边 ❌ 不能用Dijkstra

🚨 六、408最容易掉进去的几个坑

❌ 坑1:最短路径都用Dijkstra

不是!

无权图优先想到BFS。

❌ 坑2:Dijkstra能处理负权边

不能。

Dijkstra的重要前提:

边权不能为负。

❌ 坑3:Floyd只能用于带权图

也不是。

无权图也可以使用,只需要把:

有边 → 1

无边 → ∞

即可。

❌ 坑4:BFS只能求遍历顺序

错!

BFS除了遍历,还可以解决:

无权图的单源最短路径问题。

🧩 七、最后给你一个"考场判断口诀"

看到最短路径题,先别急着写代码。

先问自己三个问题:

① 有没有权值?

没有权值 → BFS

② 有权值,但是问一个源点到其他所有点?

Dijkstra

③ 问任意两个顶点之间?

Floyd

直接记:

🟢 无权看BFS

🔵 带权看Dijkstra

🟣 全点看Floyd

📖 408最短路径,真正要掌握的其实就这几件事

BFS:

dist\[\]

path\[\]

队列

逐层扩展

Dijkstra:

dist\[\]

path\[\]

final\[\]

选最小

松弛

Floyd:

dist\[\]\[\]

k作为中间点

min更新

三重循环

不要一上来就死背代码。

先把"这道题到底应该用谁"判断对,代码基本就已经成功一半了。 🚀

#408考研 #计算机考研 #数据结构 #最短路径 #BFS #Dijkstra #Floyd #算法 #考研408 #数据结构笔记 #考研学习 #计算机考研408

相关推荐
Escalating_xu1 小时前
【C++ string 上篇】从字符串基础到容量管理、迭代器与经典算法题
java·c++·算法
Keven_111 小时前
算法札记:ACM中将高精度算法融于题目的模板
算法·acm·精度
小七在进步1 小时前
数据结构:快速排序
数据结构·算法·排序算法
闻缺陷则喜何志丹1 小时前
【计算几何 第十一章】凸包:混合物
数学·算法·计算几何·凸包·混合物·凸组合
土司大王1 小时前
LeetCode hot100——二叉树的最大深度
算法·leetcode·职场和发展
高亦真2 小时前
今天是学习嵌入式的第31天
linux·学习·算法
让学习成为一种生活方式2 小时前
黄花蒿LHC基因家族的串联重复驱动扩张及其UV-B胁迫适应性--BMC Plant Biology
人工智能·算法·机器学习
ECT-OS-JiuHuaShan2 小时前
共轭互逆链路论,彻底打击庸俗辩证法和不可知论
数据库·人工智能·算法·机器学习·数学建模
薛定e的猫咪2 小时前
【大模型量化】使用 llama.cpp 完成量化、本地推理与服务化部署
人工智能·深度学习·算法·llama