IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 图的遍历——BFS、DFS -> 正文阅读

[数据结构与算法]图的遍历——BFS、DFS

一、深度优先搜索(Depth First Search,DFS)

该算法与二叉树的先序遍历类似,在第一次经过一个顶点时就进行访问操作,并记录该顶点已经被访问。具体步骤如下:

  1. 设置指针p,指向顶点v。
  2. 访问p所指的顶点,并使p指向与其相邻接的且未被访问过的顶点。
  3. 如果p所指的顶点存在,则重复步骤(2),否则执行步骤(4)。
  4. 沿着刚才访问的次序和方向回溯到一个尚有邻接顶点且未被访问过的顶点,并使p指向这个顶点。然后重复步骤(2),直到所有的顶点均被访问为止。

假设有图表示如下:

在这里插入图片描述

以邻接表的数据格式表示为:

在这里插入图片描述

假设从0顶点开始遍历,那么遍历的结点为:

0 4 2 6 7
// 其它顶点从0出发遍历不到,因为顶点0通过有向边访问不到它们。
// 如果需要将其它顶点也打印,加个循环即可。

?

示例代码

#include <iostream>
#include <vector>
#include <queue>
using namespace std;

#define MAX_NODE 20     // 图中顶点数目的最大值

struct ArcNode          // 邻接链表的表结点
{
    int adjVex;                 // adjacent vertex 邻接顶点的顶点序号
    double weight;              // 弧的权值
    struct ArcNode* nextNode;   // 指向下一个邻接顶点
};

struct AdjHead          // 邻接链表的头结点
{
    int data;                   // 顶点表示的数据,用一个数字表示
    struct ArcNode* firstNode;  // 指向第一个邻接顶点
};
using AdjList = vector<AdjHead>;    // 邻接表

struct Graph
{
    int vNum;           // 图中顶点的数目
    AdjList adjList;
};

int visited[MAX_NODE] = {0};    // 记录图中的顶点有没有被访问过

// Breadth First Search
void BFS(const Graph& g)
{
    int visited[MAX_NODE] = {0};             // 记录图中的顶点有没有被访问过
    queue<int> q;                            // 创建一个队列
    for (int i = 0; i < g.vNum; i++) {
        if (visited[i] == 0) {               // 顶点i未被访问过
            q.push(i);
            cout << i << " ";
            visited[i] = 1;                  // 顶点i标记为访问过

            while(!q.empty()) {              // 如果队列不为空,则继续取顶点进行BFS
                int k = q.front();
                q.pop();
                ArcNode* n = g.adjList[k].firstNode;
                while(n != nullptr) {        // 检查所有与顶点k的邻接顶点
                    int j = n->adjVex;
                    if (visited[j] == 0) {   // 如果邻接顶点j未被访问过,将j加入队列
                        q.push(j);
                        cout << j << " ";
                        visited[j] = 1;
                    }
                    n = n->nextNode;
                }
            }
        }
    }
}

int main()
{
    AdjList adjList;
    adjList.resize(MAX_NODE);
    ArcNode n1{4, 1.0, nullptr};
    ArcNode n2{6, 1.0, nullptr};
    ArcNode n3{0, 1.0, &n2};
    ArcNode n4{6, 1.0, nullptr};
    ArcNode n5{0, 1.0, &n4};
    ArcNode n6{1, 1.0, nullptr};
    ArcNode n7{7, 1.0, nullptr};
    ArcNode n8{2, 1.0, &n7};
    ArcNode n9{7, 1.0, nullptr};
    ArcNode n10{1, 1.0, &n9};
    ArcNode n11{6, 1.0, nullptr};
    adjList[0] = AdjHead{0, &n1};
    adjList[1] = AdjHead{1, &n3};
    adjList[2] = AdjHead{2, &n5};
    adjList[3] = AdjHead{3, &n6};
    adjList[4] = AdjHead{4, &n8};
    adjList[5] = AdjHead{5, &n10};
    adjList[7] = AdjHead{7, &n11};
    Graph g{8, move(adjList)};
    DFS(g, 0);
    //BFS(g);

    return 0;
}

?

算法复杂度

深度优先遍历图的过程实质上是对某个顶点查找其邻接点的过程,其耗费的时间取决于所采用的存储结构。当图用邻接矩阵表示时,查找所有顶点的邻接点所需时间为O(n2)。以邻接表作为存储结构时,深度优先搜索遍历图的时间复杂度为O(n+e)。

?


二、广度优先搜索(Breadth First Search,BFS)

广度优先搜索方法为:从图中的某个顶点v出发,在访问了v之后依次访问v的各个未被访问过的邻接点,然后分别从这些邻接点出发依次访问它们的邻接点,并使先被访问的顶点的邻接点先于后被访问的顶点的邻接点被访问,直到图中所有已被访问的顶点的相邻点都被访问到。若此时还有未被访问的顶点,则另选图中的一个未被访问的顶点作为起点,重复上述过程,直到图中所有的顶点都被访问到为止。

示例代码

// Depth First Search
void DFS(const Graph& g, int i) {
    cout << i << " ";      // 访问序号为i的顶点
    visited[i] = 1;         // 标记已经被访问过

    ArcNode* n = g.adjList[i].firstNode;     // 取顶点i的第一个邻接顶点
    while (n != nullptr) {                   // 检查所有与i顶点相邻接的顶点
        int j = n->adjVex;
        if (visited[j] == 0) {               // 如果顶点j未被访问,则从顶点j出发进行DFS
            DFS(g, j);
        }
        n = n->nextNode;                     // 继续遍历下一个邻接顶点
    }
}

输出结果为:

0 4 2 7 6 1 3 5

算法复杂度

遍历图的过程实质上通过边或弧找邻接点的过程,因为BFSDFS遍历图的算法时间复杂度相同,其不同之处仅仅在于对顶点访问的次序不同。

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-04-06 23:27:37  更:2022-04-06 23:29:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 9:40:05-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码