数据结构与C++ 知识量:9 - 32 - 91
深度优先搜索(Depth-First Search,DFS)是一种用于遍历或搜索树或图的算法。这个算法会尽可能深地搜索树的分支。当节点v的所在边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。
以下是深度优先搜索的基本步骤:
创建一个堆栈并将起始节点推入堆栈。
当堆栈不为空时,重复以下步骤:
a. 弹出堆栈顶部的节点。
b. 如果该节点未被访问过,标记它为已访问,并输出它。
c. 将该节点的所有未被访问过的邻接点推入堆栈。
如果某个节点的所有邻接点都已被访问,那么就回溯到堆栈中上一个节点,并继续搜索。
当堆栈为空时,表示所有的节点都已被访问过,算法结束。
深度优先搜索的时间复杂度取决于具体的数据结构。对于树或图的遍历,时间复杂度为O(n),其中n是节点的数量。对于稠密图,由于存在大量的边,时间复杂度可能会更高。
以下是使用C++表示深度优先搜索的示例代码:
#include <iostream> #include <vector> using namespace std; const int MAX_SIZE = 100; // 最大节点数 // 定义图的邻接表表示 vector<int> adjList[MAX_SIZE]; // 邻接表数组 bool visited[MAX_SIZE]; // 记录节点是否被访问过 // 深度优先搜索函数 void dfs(int v) { visited[v] = true; // 标记节点v为已访问 cout << v << " "; // 输出节点v的值 for (int i = 0; i < adjList[v].size(); i++) { // 遍历节点v的所有邻接点 int u = adjList[v][i]; if (!visited[u]) { // 如果邻接点u未被访问过,则继续递归访问u dfs(u); } } } int main() { int n, m; // n为节点数,m为边数 cin >> n >> m; // 输入节点数和边数 for (int i = 0; i < m; i++) { // 输入每条边的起点和终点,构建邻接表 int u, v; cin >> u >> v; adjList[u].push_back(v); // 将边加入邻接表 } for (int i = 1; i <= n; i++) { // 遍历每个节点,进行深度优先搜索 if (!visited[i]) { // 如果节点i未被访问过,则开始搜索 dfs(i); } } return 0; }
这个代码示例使用邻接表来表示图,并使用一个布尔数组visited来记录每个节点是否被访问过。在主函数中,首先输入节点数和边数,然后输入每条边的起点和终点,构建邻接表。接下来,遍历每个节点,如果该节点未被访问过,则调用dfs函数进行深度优先搜索。在dfs函数中,首先标记当前节点为已访问,并输出该节点的值。然后遍历当前节点的所有邻接点,如果某个邻接点未被访问过,则递归地调用dfs函数继续搜索。当所有的节点都被访问过后,算法结束。
广度优先搜索(Breadth-First Search,BFS)是一种用于遍历或搜索树或图的算法。这个算法从根节点开始,探索邻近节点,然后是下一层级的节点,以此类推。
以下是广度优先搜索的基本步骤:
创建一个队列并将起始节点放入队列中。
当队列不为空时,重复以下步骤:
a. 从队列中取出一个节点。
b. 如果该节点未被访问过,标记它为已访问,并输出它。
c. 将该节点的所有未被访问过的邻接点放入队列。
如果某个节点的所有邻接点都已被访问,那么就回溯到队列中上一个节点,并继续搜索。
当队列为空时,表示所有的节点都已被访问过,算法结束。
广度优先搜索的时间复杂度取决于具体的数据结构。对于树或图的遍历,时间复杂度为O(n),其中n是节点的数量。对于稠密图,由于存在大量的边,时间复杂度可能会更高。
以下是使用C++表示广度优先搜索的示例代码:
#include <iostream> #include <queue> #include <vector> using namespace std; const int MAX_SIZE = 100; // 最大节点数 // 定义图的邻接表表示 vector<int> adjList[MAX_SIZE]; // 邻接表数组 bool visited[MAX_SIZE]; // 记录节点是否被访问过 // 广度优先搜索函数 void bfs(int v) { queue<int> q; // 创建一个队列 q.push(v); // 将起始节点放入队列中 visited[v] = true; // 标记起始节点为已访问 while (!q.empty()) { // 当队列不为空时,重复以下步骤 int u = q.front(); // 从队列中取出一个节点 q.pop(); // 出队 cout << u << " "; // 输出节点u的值 for (int i = 0; i < adjList[u].size(); i++) { // 遍历节点u的所有邻接点 int w = adjList[u][i]; if (!visited[w]) { // 如果邻接点w未被访问过,则将其放入队列中 q.push(w); visited[w] = true; // 标记邻接点w为已访问 } } } } int main() { int n, m; // n为节点数,m为边数 cin >> n >> m; // 输入节点数和边数 for (int i = 0; i < m; i++) { // 输入每条边的起点和终点,构建邻接表 int u, v; cin >> u >> v; adjList[u].push_back(v); // 将边加入邻接表 } for (int i = 1; i <= n; i++) { // 遍历每个节点,进行广度优先搜索 if (!visited[i]) { // 如果节点i未被访问过,则开始搜索 bfs(i); } } return 0; }
Copyright © 2017-Now pnotes.cn. All Rights Reserved.
编程学习笔记 保留所有权利
MARK:3.0.0.20240214.P35
From 2017.2.6