DFS 是深度优先算法的英文简写。
A:正确。DFS 是 Depth First Search 的英文缩写,即深度优先搜索,遍历时优先沿一条分支向深处扩展,是图与树的经典搜索算法。
在宽度优先搜索中,通常使用队列来辅助实现。
A:正确。BFS 按层扩展,需要先入队的结点先出队,队列的 FIFO 特性正好保证逐层顺序访问,是 BFS 的标准辅助结构。
在深度优先搜索中,通常使用队列来辅助实现。
B:错误。DFS 要后进先出地回溯,通常用栈或递归辅助实现;队列是 BFS 按层扩展时使用的辅助结构,两者用途不同,不能互换。
在非递归实现的树的广度优先搜索中,通常使用栈来辅助实现。
B:错误。广度优先搜索按层扩展、先入先出,非递归实现用队列辅助;栈是深度优先搜索(DFS)的辅助结构,二者不可互换。,二者不可互换。
阅读以下二叉树的广度优先搜索代码:
01#include <iostream> 02#include <queue> 03 04using namespace std; 05 06// 二叉树节点的定义 07struct TreeNode { 08 int val; 09 TreeNode* left; 10 TreeNode* right; 11 TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} 12}; 13 14// 宽度优先搜索 (BFS) 迭代实现 15TreeNode* bfs(TreeNode* root, int a) { 16 if (root == nullptr) return nullptr; 17 18 queue<TreeNode*> q; 19 q.push(root); 20 21 while (!q.empty()) { 22 TreeNode* node = q.front(); 23 q.pop(); 24 25 if (node->val == a) 26 return node; 27 28 cout << node->val << " "; // 先访问当前节点 29 30 if (node->left) q.push(node->left); // 将左子节点入队 31 if (node->right) q.push(node->right); // 将右子节点入队 32 } 33 return nullptr; 34}
使用以上算法,在以下这棵树搜索数值 20 时,可能的输出是( )。
C:树为 5(2(-4,3), 17(9,20))。BFS 按层出队:5、2、17、-4、3、9,之后轮到 20 命中即返回,故输出 5 2 17 -4 3 9,选 C。
阅读以下二叉树的深度优先搜索代码:
01#include <iostream> 02#include <stack> 03 04using namespace std; 05 06// 非递归深度优先搜索 (DFS) 07TreeNode* dfs(TreeNode* root, int a) { 08 if (root == nullptr) return nullptr; 09 10 stack<TreeNode*> stk; 11 stk.push(root); 12 13 while (!stk.empty()) { 14 TreeNode* node = stk.top(); 15 stk.pop(); 16 if (node->val == a) 17 return node; 18 19 cout << node->val << " "; // 访问当前节点 20 21 if (node->right) stk.push(node->right); // 先压入右子节点 22 if (node->left) stk.push(node->left); // 再压入左子节点 23 } 24 return nullptr; 25}
使用以上算法,在二叉树搜索数值 20 时,可能的输出是( )。
A:树为 5(2(-4,3), 17(9,20))。非递归 DFS 先压右子再压左子:5→2→-4→3→17→9,随后 20 命中返回,输出 5 2 -4 3 17 9。
阅读以下二叉树的深度优先搜索算法,横线上应填写()。
01void dfs(TreeNode* root) { 02 if (root == nullptr) 03 return; 04 05 stack<TreeNode*> s; 06 s.push(root); 07 while (!s.empty()) { 08 ____________ // 在此处填入代码 09 cout << node->value << " "; 10 11 if (node->right) s.push(node->right); 12 if (node->left) s.push(node->left); 13 } 14}
B:非递归 DFS 用栈,先取栈顶 TreeNode* node=s.top() 再 s.pop() 弹出,随后输出并压入右、左孩子;栈无 front 操作,A 不弹出会死循环。
阅读以下二叉树的广度优先搜索的代码,横线上应填写()。
01#include <queue> 02void bfs(TreeNode* root) { 03 if (root == NULL) return; 04 05 queue<TreeNode*> q; 06 q.push(root); 07 while (!q.empty()) { 08 ____________ // 在此处填入代码 09 cout << node->val << " "; 10 if (node->left) { 11 q.push(node->left); 12 } 13 if (node->right) { 14 q.push(node->right); 15 } 16 } 17}
D:BFS 用队列,取队首 q.front() 并 q.pop() 出队后输出,再入队左右孩子;栈才用 top,A、B 对队列无效。
使用宽度优先搜索(BFS)遍历以下这棵树,可能的输出是( )。
1 / \ 2 3 / \ \ 8 9 6 / \ \ 4 5 7
C:BFS 按层输出:第 1 层 1,第 2 层 2 3,第 3 层 8 9 6,第 4 层 4 5 7,合并得 1 2 3 8 9 6 4 5 7。
请将下面 C++ 实现的深度优先搜索(DFS)代码补充完整,横线处应填入()。
01struct TreeNode { 02 int val; 03 TreeNode* left; 04 TreeNode* right; 05 TreeNode(int x): val(x), left(nullptr), right(nullptr) {} 06}; 07 08void dfs(TreeNode* root, vector<int>& result) { 09 if (root == nullptr) return; 10 11 ____________ 12}
A:DFS 先访问当前结点把值加入 result,再递归左子树、右子树,即根左右的先序递归;B、C、D 访问 root->left->val 在左孩子为空时会出错。
给定一个二叉树,返回每一层中最大的节点值,结果以数组形式返回,横线处应填入()。
01#include <vector> 02#include <queue> 03#include <algorithm> 04 05struct TreeNode { 06 int val; 07 TreeNode* left; 08 TreeNode* right; 09 TreeNode(int x): val(x), left(nullptr), right(nullptr) {} 10}; 11 12vector<int> largestValues(TreeNode* root) { 13 vector<int> result; 14 if (!root) return result; 15 16 queue<TreeNode*> q; 17 q.push(root); 18 19 while (!q.empty()) { 20 int sz = q.size(); 21 int maxVal = INT_MIN; 22 for (int i = 0; i < sz; ++i) { 23 TreeNode* node; 24 ____________ 25 maxVal = max(maxVal, node->val); 26 if (node->left) q.push(node->left); 27 if (node->right) q.push(node->right); 28 } 29 result.push_back(maxVal); 30 } 31 32 return result; 33}
D:每层先取队首 node=q.front() 再 q.pop() 出队,随后更新该层最大值并入队左右孩子;C 先 pop 再取 front 会取到下一个结点,A、B 不弹出会死循环。
令 是树的节点数,下面代码实现了树的广度优先遍历,其时间复杂度是()。
01void bfs(TreeNode* root) { 02 if (!root) return; 03 queue<TreeNode*> q; 04 q.push(root); 05 while (!q.empty()) { 06 TreeNode* node = q.front(); 07 q.pop(); 08 cout << node->val << " "; 09 if (node->left) q.push(node->left); 10 if (node->right) q.push(node->right); 11 } 12}
A:O(n)。BFS 中每个结点入队、出队各一次,出队时访问左右孩子,总操作次数与结点数 n 成正比,时间复杂度 O(n)。
下列代码实现了树的深度优先遍历,则横线处应填入()。
01struct TreeNode { 02 int val; 03 TreeNode* left; 04 TreeNode* right; 05 TreeNode(int x): val(x), left(nullptr), right(nullptr) {} 06}; 07 08void dfs(TreeNode* root) { 09 if (!root) return; 10 stack<TreeNode*> st; 11 st.push(root); 12 while (!st.empty()) { 13 TreeNode* node = st.top(); st.pop(); 14 cout << node->val << " "; 15 if (node->right) st.push(node->right); 16 ____________ 17 } 18}
A:非递归 DFS 先压右孩子再压左孩子,故填 if(node->left) st.push(node->left),保证左子树先出栈访问;B、C 不是栈的入栈操作,D 会重复压右孩子。
给定一棵二叉树,采用广度优先搜索(BFS)算法,返回右视图所有节点的值。其中右视图定义为:二叉树的右视图是从树的右侧看过去时可见的节点集合,即右视图中的每个节点都是某一层中最右侧的节点。
01struct TreeNode { 02 int val; 03 TreeNode* left; 04 TreeNode* right; 05 TreeNode(int x): val(x), left(nullptr), right(nullptr) {} 06}; 07 08vector<int> rightSideView(TreeNode* root) { 09 unordered_map<int, int> rightmostValueAtDepth; 10 int max_depth = -1; 11 12 queue<TreeNode*> nodeQueue; 13 queue<int> depthQueue; 14 nodeQueue.push(root); 15 depthQueue.push(0); 16 17 while (!nodeQueue.empty()) { 18 TreeNode* node = nodeQueue.front(); nodeQueue.pop(); 19 int depth = depthQueue.front(); depthQueue.pop(); 20 21 if (node != NULL) { 22 max_depth = max(max_depth, depth); 23 rightmostValueAtDepth[depth] = node->val; 24 nodeQueue.push(node->left); 25 nodeQueue.push(node->right); 26 depthQueue.push(____________); 27 depthQueue.push(____________); 28 } 29 } 30 31 vector<int> rightView; 32 for (int depth = 0; ____________; ++depth) { 33 rightView.push_back(rightmostValueAtDepth[depth]); 34 } 35 return rightView; 36}
B:左右孩子深度都加 1,两个横线填 depth+1;收集右视图时 depth 从 0 到 max_depth 都要取,故第三个横线填 depth<=max_depth。
下列关于树的深度优先搜索(DFS)的说法中,正确的是()。
C:DFS 需后进先出地回溯,常借助递归或栈实现;A 不一定按层从上到下,B 访问子结点顺序可变、序列不唯一,D DFS 同样适用于普通多叉树。
在二叉树中,宽度优先搜索算法(BFS)保证从起点到每个节点的访问路径是边数最少的路径(即最短路径)。
A:正确。BFS 按层逐层扩展,第一次访问到某结点时经过的边数必然最少,因此在无权图中 BFS 保证最短路径(边数最少)。
给定一个无向图,图的节点编号从 0 到 n-1,图的边以邻接表的形式给出。下面的程序使用深度优先搜索(DFS)遍历该图,并输出遍历的节点顺序。横线处应该填入的是( )
01#include <iostream> 02#include <vector> 03#include <stack> 04using namespace std; 05void DFS(int start, vector<vector<int>>& graph, vector<bool>& visited) { 06 stack<int> s; 07 s.push(start); 08 visited[start] = true; 09 while (!s.empty()) { 10 int node = s.top(); 11 s.pop(); 12 cout << node << " "; // 输出当前节点 13 // 遍历邻接节点 14 for (int neighbor : graph[node]) { 15 if (!visited[neighbor]) { 16 ____________ 17 ____________ 18 } 19 } 20 } 21} 22int main() { 23 int n, m; 24 cin >> n >> m; 25 vector<vector<int>> graph(n); 26 for (int i = 0; i < m; i++) { 27 int u, v; 28 cin >> u >> v; 29 graph[u].push_back(v); 30 graph[v].push_back(u); 31 } 32 vector<bool> visited(n, false); 33 // 从节点 0 开始DFS遍历 34 DFS(0, graph, visited); 35 return 0; 36}
D:栈式 DFS 需先标记 visited[neighbor]=true 防止重复入栈,再把 neighbor 压入栈顶,两处分别填这两句。
泛洪算法的递归实现容易造成溢出,因此大的二维地图算法中,一般使用广度优先搜索实现。
对。泛洪递归实现易发生栈溢出,大二维地图一般改用 BFS(队列)实现,避免递归层数过深;递归实现仅适用于小地图;但递归写法代码更简洁,小地图可用。
在图像处理或游戏开发中,泛洪(flood fill)算法既可以⽤BFS实现,也可以⽤DFS实现。
对。泛洪填充既可用 BFS(队列)实现,也可用 DFS(递归或显式栈)实现,两种方式都可行;用栈或队列实现均可,取决于实现方式,故对。
下面程序片段主要体现的算法思想是( )。
01void dfs(int x, int y) { 02 vis[x][y] = true; 03 for (int k = 0; k < 4; k++) { 04 int nx = x + dx[k], ny = y + dy[k]; 05 if (inside(nx, ny) && a[nx][ny] == 1 && !vis[nx][ny]) 06 dfs(nx, ny); 07 } 08}
A:从起点按四方向扩散标记连通的 1 区域,是典型的泛洪算法(Flood Fill,DFS 实现);Flood Fill 也可用 BFS 实现。
同一个图从同一个起点进行深度优先搜索,访问序列一定与邻接点的枚举顺序无关。
错。DFS 访问序列取决于邻接点的枚举顺序,同一图同一起点按不同顺序枚举邻点会得到不同序列;不同枚举顺序对应不同访问序列,故错。
深度优先搜索(DFS)在遍历图时,每当访问到某个顶点后,选择⼀个相邻的未访问顶点继续搜索,直到某个顶点的所有相邻顶点均已被访问,则退回到前⼀顶点继续搜索。该算法主要运⽤了( )。
D:DFS 访问一个顶点后沿未访问邻点深入,走不通则退回上一顶点换路继续,正是回溯思想;与递归调用栈的回退过程一致;与递归调用的回退机制一致。
无向图的边为 ,,,,。从顶点 开始进行 BFS,每轮根据出队顶点,将与其相邻顶点按编号从小到大入队,则顶点 第一次入队时,队列的状态为( )。
C:BFS 从 1 出发:先入队 2、3;出队 2 时入队 4,此时队列为 [3,4],即顶点 4 第一次入队时的队列状态。故选 C。
下列关于深度优先搜索和广度优先搜索的说法,错误的是( )。
D:二叉树后序遍历是深度优先(先左后右再根),不是广度优先;BFS 必须按层次逐层访问节点,故 D 说法错误,其余选项均正确,故选 D。
下面的程序属于哪种算法( )。
01int pos[8]; 02void queen(int n) { 03 for (int i = 0; i < 8; i++) { 04 pos[n] = i; 05 bool attacked = false; 06 for (int j = 0; j < n; j++) 07 if (pos[n] == pos[j] || pos[n] + n == pos[j] + j || pos[n] - n == pos[j] - j) { 08 attacked = true; 09 break; 10 } 11 if (attacked) 12 continue; 13 if (n == 7) { 14 return; 15 } else { 16 queen(n + 1); 17 } 18 } 19}
C:queen 逐行尝试放子,冲突则 continue,否则递归下一行并回溯换列,是典型的深度优先搜索(回溯法)实现八皇后。故选 C。
围棋游戏中,判断落下一枚棋子后是否会提掉对方的子,可以使用泛洪算法来实现。( )
对。判断提子需找出被围棋子所在连通块并统计气数,用泛洪填充(Flood Fill,BFS/DFS 扩散)遍历连通块即可实现。故正确。
下列选项中,哪个可能是下图的深度优先遍历序列( )。
C:DFS 能走就走:A 中 5 之后应继续访问其未访问邻点 6 而非 4;B 中 3 之后应为 7;D 中 8 之后应为 5;只有 C 与图吻合。
下列选项中,哪个可能是下图的广度优先遍历序列( )。
A:BFS 逐层扩散:从 1 出发第一层访问其邻点 3、5、7,第二层 4、2,第三层 6、8、9;其余选项层次顺序与图中邻接关系不符。
学生在读期间所上的某些课程中需要先上其他的课程,所有课程和课程间的先修关系构成一个有向图 G,有向边 <U, V> 表示课程 U 是课程 V 的先修课,则要找到某门课程 C 的全部先修课下面哪种方法不可行?( )
D:把边反向从 C 出发 BFS/DFS 都能遍历全部先修课;动态规划面向最优子结构问题,求先修课集合不是最优化问题,无法用 DP,故不可行。
广度优先搜索(BFS)能够判断图是否连通。( )
对。从任一顶点 BFS,用队列逐层扩展并标记访问,若最终能访问全部顶点则图连通,否则不连通,故 BFS 可判断连通性;DFS 从单点出发也能判断连通性。
判断图是否连通只能⽤⼴度优先搜索算法实现
B:错误。判断连通性不只 BFS 一种:DFS 从一个顶点出发看能否到达全部顶点即可;也可用并查集合并所有边后统计连通分量个数是否为 1。
有 个顶点、 条边的图的深度优先搜索遍历时间复杂度为( )。
C:O(V+E)。DFS 每个顶点入栈访问一次,邻接表每条出边被扫描一次,总耗时与 V+E 成正比;单独 O(V) 或 O(E) 都漏算另一半。
判断无向图中是否有环,可以通过广度优先搜索实现
A:正确。BFS 遍历无向图,遇到已访问且非父节点的顶点即说明存在环;DFS 同样可行,两种搜索都能判环,判断能力等价。
下⾯ pailie 函数是⼀个实现排列的程序,横线处可以填⼊的是( )。
01#include <iostream> 02using namespace std; 03int sum = 0; 04void swap(int & a, int & b) { 05 int temp = a; 06 a = b; 07 b = temp; 08} 09void pailie(int begin, int end, int a[]) { 10 if (begin == end) { 11 for (int i = 0; i < end; i++) 12 cout << a[i]; 13 cout << endl; 14 } 15 for (int i = begin; i < end; i++) { 16 ___________ // 在此处填入选项 17 } 18}
C:swap(a[begin],a[i]) 把 a[i] 固定到 begin 位,递归排列 begin+1 之后,再换回来恢复现场;A 用 begin+1 越界且撤销不对称,B 递归参数不前进会死循环,D 写法错误。
已知 pailie 函数是实现排列的程序(代码如下),主函数为如下的程序,则最后的排列数是多少个?( )。
01#include <iostream> 02using namespace std; 03int sum = 0; 04void swap(int & a, int & b) { 05 int temp = a; 06 a = b; 07 b = temp; 08} 09void pailie(int begin, int end, int a[]) { 10 if (begin == end) { 11 for (int i = 0; i < end; i++) 12 cout << a[i]; 13 cout << endl; 14 } 15 for (int i = begin; i < end; i++) { 16 swap(a[begin], a[i]); 17 pailie(begin + 1, end, a); 18 swap(a[i], a[begin]); 19 } 20}
主函数如下:
01int main() { 02 int a[5] = {1, 2, 3, 4, 5}; 03 pailie(0, 5, a); 04 return 0; 05}
A:120。pailie(0,5) 对 5 个互不相同的元素 {1,2,3,4,5} 做全排列,输出 5!=120 行,即排列数 120。