图的遍历——BFS、DFS

文章目录

    • 一、深度优先搜索(Depth First Search,DFS)
      • 示例代码
      • 算法复杂度
    • 二、广度优先搜索(Breadth First Search,BFS)
      • 示例代码
      • 算法复杂度

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

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

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

假设有图表示如下:

图的遍历——BFS、DFS_第1张图片

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

图的遍历——BFS、DFS_第2张图片

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

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

示例代码

#include 
#include 
#include 
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;    // 邻接表

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 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遍历图的算法时间复杂度相同,其不同之处仅仅在于对顶点访问的次序不同。

你可能感兴趣的:(算法与数据结构,DFS,BFS,图的遍历)