数据结构与C++

数据结构与C++ 知识量:9 - 32 - 91

7.3 图的遍历><

深度优先搜索- 7.3.1 -

深度优先搜索(Depth-First Search,DFS)是一种用于遍历或搜索树或图的算法。这个算法会尽可能深地搜索树的分支。当节点v的所在边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。

以下是深度优先搜索的基本步骤:

  1. 创建一个堆栈并将起始节点推入堆栈。

  2. 当堆栈不为空时,重复以下步骤:
    a. 弹出堆栈顶部的节点。
    b. 如果该节点未被访问过,标记它为已访问,并输出它。
    c. 将该节点的所有未被访问过的邻接点推入堆栈。

  3. 如果某个节点的所有邻接点都已被访问,那么就回溯到堆栈中上一个节点,并继续搜索。

  4. 当堆栈为空时,表示所有的节点都已被访问过,算法结束。

深度优先搜索的时间复杂度取决于具体的数据结构。对于树或图的遍历,时间复杂度为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函数继续搜索。当所有的节点都被访问过后,算法结束。

广度优先搜索- 7.3.2 -

广度优先搜索(Breadth-First Search,BFS)是一种用于遍历或搜索树或图的算法。这个算法从根节点开始,探索邻近节点,然后是下一层级的节点,以此类推。

以下是广度优先搜索的基本步骤:

  1. 创建一个队列并将起始节点放入队列中。

  2. 当队列不为空时,重复以下步骤:
    a. 从队列中取出一个节点。
    b. 如果该节点未被访问过,标记它为已访问,并输出它。
    c. 将该节点的所有未被访问过的邻接点放入队列。

  3. 如果某个节点的所有邻接点都已被访问,那么就回溯到队列中上一个节点,并继续搜索。

  4. 当队列为空时,表示所有的节点都已被访问过,算法结束。

广度优先搜索的时间复杂度取决于具体的数据结构。对于树或图的遍历,时间复杂度为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;  
}