当前位置: 首页 > news >正文

图论专题(一):Hello, Graph! 掌握“建图”与“遍历”的灵魂

哈喽各位,我是前端小L。

欢迎来到我们的新专题——“图论”!准备好,我们的思维即将从“一条线”升维到一张“网”。

今天,我们将从图论最基础、最核心的问题开始:A点和B点,是连通的吗? 这个问题看似简单,却蕴含了后续所有复杂图算法的基础。我们将用它来““磨刀”,彻底掌握图的表示和遍历。

力扣 1971. 寻找图中是否存在路径

https://leetcode.cn/problems/find-if-path-exists-in-graph/

题目分析:

  • 输入n (顶点数, 0到n-1),edges (一个 [u, v] 列表),source (起点),destination (终点)。

  • 图的类型无向图[u, v] 意味着 uv 之间有一条双向的路。

  • 目标:判断从 source 出发,能否“走”到 destination

第一关:如何把“边”建成“地图”?—— 邻接表

计算机并不“认识” [[0, 1], [1, 2], [0, 2]] 这种“边列表”。它太慢了,要找 0 的邻居,我们得遍历整个列表。 我们需要一种更高效的“地图”——邻接表 (Adjacency List)

邻接表在 C++ 中,就是一个“向量的向量”:vector<vector<int>> graph(n);

  • graph 是一个大 vector,长度为 n

  • graph[i] 是一个小 vector,里面存储了所有与 i 直接相连的邻居。

建图过程 (O(E)): 我们遍历 edges 列表(E 是边的数量),对于每一条边 [u, v]

  1. graph[u].push_back(v); (添加一条 u -> v 的路)

  2. graph[v].push_back(u); (因为是无向图,还要添加 v -> u 的路)

C++

// 1. 建图 (邻接表)
vector<vector<int>> graph(n);
for (const auto& edge : edges) {int u = edge[0];int v = edge[1];graph[u].push_back(v);graph[v].push_back(u); // 无向图,双向添加
}

第二关:如何“走”这张地图?—— DFS 与 BFS

有了地图,我们就可以从 source 出发“探险”了。有两种经典的探险策略:

  1. DFS (深度优先搜索):像在走迷宫,“一条路走到黑”

    • 策略:从 source 出发,访问它的第一个邻居 v1,然后再访问 v1 的第一个邻居 v2... 直到走到“死胡同”,再回溯(返回上一层),去探索 v1 的第二个邻居。

    • 实现:通常用递归

  2. BFS (广度优先搜索):像“水波纹”一样,“一层一层地向外扩散”

    • 策略:从 source 出发(第0层),访问它所有“一度人脉”(邻居,第1层),然后再访问所有“二度人脉”(邻居的邻居,第2层)...

    • 实现:通常用队列 (Queue)

“Aha!”时刻:防止“兜圈”的灵魂—— visited 数组

无论DFS还是BFS,我们都会遇到一个致命问题: [0, 1] 这条边,graph[0] 里有 1graph[1] 里有 0

  • DFS: dfs(0) -> 看到邻居 1 -> 调用 dfs(1)

  • dfs(1) -> 看到邻居 0 -> 调用 dfs(0)

  • dfs(0) -> 看到邻居 1 -> 调用 dfs(1)

  • ... 栈溢出 (Stack Overflow)!

解决方案:我们需要一个“足迹”数组,走过的地方就不要再走了! vector<bool> visited(n, false);

遍历的“铁律”

  1. (BFS):当一个节点入队 (push) 时,必须立刻标记 visited[node] = true

  2. (DFS):在 dfs(node) 函数的第一行必须立刻标记 visited[node] = true

代码实现 (O(V+E) 时间, O(V+E) 空间)

我们提供两种解法,它们的核心思想都是“遍历”。

解法一:DFS (递归)

class Solution {
public:bool validPath(int n, vector<vector<int>>& edges, int source, int destination) {// 1. 建图 (邻接表)vector<vector<int>> graph(n);for (const auto& edge : edges) {graph[edge[0]].push_back(edge[1]);graph[edge[1]].push_back(edge[0]);}// 2. “灵魂”:visited 数组vector<bool> visited(n, false);// 3. 启动 DFSdfs(source, graph, visited);// 4. 检查终点是否被访问到return visited[destination];}void dfs(int u, vector<vector<int>>& graph, vector<bool>& visited) {// “铁律”:立刻标记visited[u] = true;// 探索所有邻居for (int v : graph[u]) {if (!visited[v]) {dfs(v, graph, visited);}}}
};

解法二:BFS (队列)

C++

#include <queue> // 引入队列class Solution {
public:bool validPath(int n, vector<vector<int>>& edges, int source, int destination) {// 1. 建图vector<vector<int>> graph(n);for (const auto& edge : edges) {graph[edge[0]].push_back(edge[1]);graph[edge[1]].push_back(edge[0]);}vector<bool> visited(n, false);queue<int> q;// 3. 启动 BFSq.push(source);visited[source] = true; // “铁律”:入队时立刻标记while (!q.empty()) {int u = q.front();q.pop();if (u == destination) {return true; // 可以在这里提前退出}// 探索所有邻居for (int v : graph[u]) {if (!visited[v]) {visited[v] = true; // “铁律”:入队时立刻标记q.push(v);}}}// 4. 检查终点是否被访问到return visited[destination];}
};

深度复杂度分析

  • V (Vertices):顶点数,即 n

  • E (Edges):边数,即 edges.size()

  • 时间复杂度 O(V + E)

    • 建图:需要 O(E) 时间,因为我们遍历了 edges 数组一次。

    • 遍历 (DFS/BFS):我们需要访问每个顶点 V 最多一次(因为 visited 数组的保护)。在访问每个顶点 u 时,我们会遍历它的所有邻居,这相当于遍历了它的所有“出边”。对于整个图,所有“出边”的总和,在无向图中等于 2 * E

    • 总时间 = O(E) + O(V + 2E) = O(V + E)

  • 空间复杂度 O(V + E)

    • 邻接表 graph:需要存储所有的边,总空间是 O(V + E)。

    • visited 数组:需要 O(V) 空间。

    • 辅助空间:DFS 需要 O(V) 的递归栈空间(最坏情况,如一条长链);BFS 需要 O(V) 的队列空间(最坏情况,如一个“星型图”)。

    • 总空间 = O(V + E) + O(V) = O(V + E)

总结

今天,我们为“图论”专题打下了最坚实的地基。我们学会了:

  1. 邻接表 vector<vector<int>> 来“建图”。

  2. 图的遍历有 DFS(递归)和 BFS(队列)两种核心方式。

  3. visited 数组是防止无限循环的“灵魂”。

在下一篇中,我们将把今天学到的 DFS/BFS,应用到最常见的“隐式图”——二维网格(“岛屿问题”)上!

下期见!

http://www.dtcms.com/a/604946.html

相关文章:

  • 做彩票网站能挣到钱吗中国最好的购物平台
  • 南京做网站群的公司岳西县住房和城乡建设局网站
  • 前端高频面试题之Vue(高级篇)
  • 【附源码】告别静态密码!openHiTLS 开源一次性密码协议(HOTP/TOTP),推动动态认证普及
  • UniApp 小程序中使用地图组件
  • 25华北理工大学考情数据分析
  • Unity Shader Graph 3D 实例 - 基础的模型贴图渲染
  • 17.TCP编程
  • Java高级特性:单元测试、反射、注解、动态代理
  • python机器学习工程化demo(包含训练模型,预测数据,模型列表,模型详情,删除模型)支持线性回归、逻辑回归、决策树、SVC、随机森林等模型
  • 逻辑回归在个性化推荐中的原理与应用
  • 织梦网站后台怎么登陆郑州知名做网站公司有哪些
  • 免费做网站的软件跨境电商自建站平台
  • 本机oracle连接延时41970 毫秒
  • 不到一块钱的带USB 2.4G收发 SOC芯片,集成2.4G射频 32位MCU
  • Ubuntu 24.04 安装 PostgreSQL
  • 数据科学每日总结--Day18--数据库
  • 【ZeroRange WebRTC】WebRTC 基于 STUN 的 srflx 直连原理与实现
  • neovim等模态编辑器最优雅的输入法解决方案
  • FaceBook叫板OpenAI!开源 Omnilingual ASR:支持1600多种语言的开源多语言语音识别
  • 分享一个MySQL万能备份脚本
  • 大模型数据洞察能力方法调研
  • 32位MCU芯片国产品牌(32系列单片机常用型号有哪些)
  • 网站底部留言代码赤峰建设淘宝网站
  • 方特网站是谁做的照片做视频的网站
  • Java 9 新特性详解
  • Spring boot 3.3.1 官方文档 中文
  • Sora 2——开启 AI 视频创作新时代
  • 异世界网络:BGP联邦的建立
  • PHP客户端调用由Go服务端GRPC接口