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

C++DFS深度优先搜索全解

C++ DFS深度优先搜索全解

深度优先搜索(Depth-First Search,DFS)是一种用于遍历或搜索树或图的算法。其核心思想是尽可能深地搜索树的分支,直到无法继续为止,然后回溯到上一个节点继续搜索。以下将详细讲解DFS在各类问题中的应用及优化方法。


DFS走迷宫

迷宫问题通常涉及从起点到终点的路径搜索。DFS通过递归或栈结构实现路径探索。

算法步骤:

  • 定义迷宫矩阵,标记起点和终点。
  • 从起点出发,依次尝试四个方向(上、下、左、右)。
  • 若当前方向可走且未被访问,则标记为已访问并递归进入下一步。
  • 若到达终点,记录路径;否则回溯并尝试其他方向。

代码示例:

#include <iostream> #include <vector> using namespace std; vector<vector<int>> maze = { {0, 1, 0, 0}, {0, 1, 1, 0}, {0, 0, 0, 0}, {0, 1, 1, 0} }; vector<vector<bool>> visited(4, vector<bool>(4, false)); bool dfs(int x, int y, int endX, int endY) { if (x == endX && y == endY) return true; if (x < 0 || x >= 4 || y < 0 || y >= 4 || maze[x][y] == 1 || visited[x][y]) return false; visited[x][y] = true; if (dfs(x + 1, y, endX, endY) || dfs(x - 1, y, endX, endY) || dfs(x, y + 1, endX, endY) || dfs(x, y - 1, endX, endY)) return true; visited[x][y] = false; return false; }

DFS解决八皇后问题

八皇后问题要求在8×8棋盘上放置8个皇后,使其互不攻击。DFS通过回溯尝试所有可能的放置方式。

算法步骤:

  • 按行放置皇后,依次尝试每一列。
  • 检查当前位置是否与已放置皇后冲突(同列、对角线)。
  • 若冲突则跳过;否则递归放置下一行。
  • 若所有行放置完成,记录解。

代码示例:

#include <vector> #include <iostream> using namespace std; vector<vector<string>> solutions; bool isValid(vector<string>& board, int row, int col) { for (int i = 0; i < row; ++i) if (board[i][col] == 'Q') return false; for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; --i, --j) if (board[i][j] == 'Q') return false; for (int i = row - 1, j = col + 1; i >= 0 && j < 8; --i, ++j) if (board[i][j] == 'Q') return false; return true; } void dfs(vector<string>& board, int row) { if (row == 8) { solutions.push_back(board); return; } for (int col = 0; col < 8; ++col) { if (isValid(board, row, col)) { board[row][col] = 'Q'; dfs(board, row + 1); board[row][col] = '.'; } } }

DFS图的遍历

DFS可用于遍历图中的所有节点,适用于无向图和有向图。

算法步骤:

  • 从起始节点开始,标记为已访问。
  • 递归访问所有未访问的相邻节点。
  • 使用邻接表或邻接矩阵存储图结构。

代码示例:

#include <vector> #include <iostream> using namespace std; vector<vector<int>> graph = {{1, 2}, {0, 3}, {0, 3}, {1, 2}}; vector<bool> visited(4, false); void dfs(int node) { visited[node] = true; cout << node << " "; for (int neighbor : graph[node]) if (!visited[neighbor]) dfs(neighbor); }

DFS无效路径优化与剪枝

剪枝通过提前终止无效分支提升效率,常见于组合优化问题。

剪枝策略:

  • 可行性剪枝:当前路径不满足约束条件时终止。
  • 最优性剪枝:当前路径已劣于已知最优解时终止。

示例:数独求解

bool isValid(vector<vector<char>>& board, int row, int col, char c) { for (int i = 0; i < 9; ++i) { if (board[row][i] == c) return false; if (board[i][col] == c) return false; if (board[3 * (row / 3) + i / 3][3 * (col / 3) + i % 3] == c) return false; } return true; } bool solveSudoku(vector<vector<char>>& board) { for (int i = 0; i < 9; ++i) { for (int j = 0; j < 9; ++j) { if (board[i][j] == '.') { for (char c = '1'; c <= '9'; ++c) { if (isValid(board, i, j, c)) { board[i][j] = c; if (solveSudoku(board)) return true; board[i][j] = '.'; } } return false; } } } return true; }

DFS的回溯机制

回溯是DFS的核心特性,通过撤销选择尝试其他可能性。

关键点:

  • 选择:尝试一个候选解。
  • 约束:检查是否满足条件。
  • 目标:确认是否完成解。
  • 撤销:回溯到上一步。

示例:全排列问题

void backtrack(vector<int>& nums, vector<vector<int>>& res, vector<int>& path) { if (path.size() == nums.size()) { res.push_back(path); return; } for (int num : nums) { if (find(path.begin(), path.end(), num) != path.end()) continue; path.push_back(num); backtrack(nums, res, path); path.pop_back(); } }

DFS在社会中的普及

DFS不仅是算法竞赛的必备技能,还广泛应用于实际场景:

  • 路径规划:GPS导航、机器人寻路。
  • 游戏开发:迷宫生成、AI决策树。
  • 网络爬虫:深度优先抓取网页链接。
  • 社交网络分析:好友关系链的深度探索。

案例:社交网络好友推荐DFS可用于遍历用户的好友关系链,发现潜在好友或社区结构。例如,通过深度遍历用户A的好友列表,推荐其好友的好友中未直接关联的用户。


总结

DFS通过递归或栈实现深度遍历,适用于路径搜索、组合问题、图遍历等场景。结合剪枝和回溯可大幅提升效率,其思想在技术和社会领域均有深远影响。

以下是DFSC++风格的伪代码实现,采用递归和迭代两种常见写法,并附简要说明:

C++伪代码

递归实现

void DFS_recursive(int node, vector<bool>& visited, const vector<vector<int>>& graph) { visited[node] = true; for (int neighbor : graph[node]) { if (!visited[neighbor]) { DFS_recursive(neighbor, visited, graph); } } }
  • 标记当前节点为已访问
  • 遍历所有未访问的相邻节点递归调用

迭代实现(使用栈)

void DFS_iterative(int start, vector<bool>& visited, const vector<vector<int>>& graph) { stack<int> s; s.push(start); visited[start] = true; while (!s.empty()) { int node = s.top(); s.pop(); for (int neighbor : graph[node]) { if (!visited[neighbor]) { visited[neighbor] = true; s.push(neighbor); } } } }
  • 初始化栈并压入起始节点
  • 每次弹出栈顶节点处理
  • 将未访问的邻居压入栈并标记

参数说明

  • graph:邻接表表示的图结构(vector<vector<int>>)
  • visited:记录节点访问状态的布尔数组
  • node/start:当前处理的节点索引

复杂度分析

  • 时间:O(V+E)(V为顶点数,E为边数)
  • 空间:递归实现受调用栈深度影响,迭代实现显式使用栈结构

实际使用时需根据图的具体表示法调整邻接节点的访问方式。对于大规模图,迭代实现通常更安全以避免栈溢出。

http://www.jsqmd.com/news/768095/

相关文章:

  • AI原生安全平台OpenClaw-Security:LLM驱动的智能安全运营实战
  • [引]langchain docs 文档
  • OpenClaw Personas:214个开箱即用AI智能体,构建你的专属数字专家团队
  • RPG Maker Decrypter终极指南:三步解锁加密游戏资源
  • 视频处理前端(VPFE)架构与中断控制机制解析
  • 别再只会用AT指令了!用EC20 4G模块+移远串口助手,5分钟搞定MQTT物联网数据上报
  • 构建企业级.NET代码编辑器:ScintillaNET终极架构解析
  • 西门子PLC数据采集(一):通过.net采集西门子PLC数据的方法
  • Navicat连不上MySQL?别慌!手把手教你排查2002错误(从服务状态到防火墙)
  • 别再只用默认参数了!mkfs.ext4格式化磁盘时,这几个参数调一调性能提升明显
  • 达梦DMRMAN备份集查看实战:从SHOW命令到XML导出,一份保姆级排查手册
  • Unity Timeline实战:用自定义对话轨道打造电影级游戏过场动画(附完整资源)
  • LinkSwift网盘直链下载助手:免费解锁九大网盘极速下载的终极指南
  • AI浏览器扩展开发实战:构建智能网页内容处理代理
  • 终极指南:C++20类类型非类型模板参数的创新应用
  • OCCT可视化系统揭秘:构建高性能3D图形渲染引擎
  • 2026高速四轴分切机厂家/高速分切机厂家推荐,精研分切技艺,赋能产业升级 - 栗子测评
  • 大语言模型在编程中的效率提升与风险防范
  • 终极Voyager代码统计报告:语言分布与复杂度深度分析
  • 本地部署ChatGPT:基于GGUF与llama.cpp的私有化AI对话实践
  • Myriade-AI:开源大模型推理优化工具包部署与调优实战
  • 智能客服对话数据收集与分类技术实践
  • 2026年4月热门的蔡司工业CT代理商推荐,手持式3d扫描仪/蔡司扫描电子显微镜,蔡司工业CT厂家推荐 - 品牌推荐师
  • Rust版LangChain:llm-chain构建高性能LLM应用实践
  • Linux死锁检测与排障实战 从Lockdep到ftrace与crash
  • 告别SegFormer!用U-MixFormer+B0在ADE20K上轻松涨点3.8%,附保姆级复现教程
  • ighack高级配置技巧:如何优化攻击性能与匿名性
  • JAVA自营商城小程序APP商城源码单商户源码的uniapp代码片段
  • 无人机巡检中输电线路缺陷检测数据集(YOLO格式)
  • Windows服务器运维:如何用PM2守护你的多个Node.js应用进程并查看日志