了解深度优先搜索(DFS)

    在本教程中,您将通过示例和伪代码了解深度优先搜索算法。此外,您还将学习在C中实现DFS。
    深度优先搜索或深度优先遍历是一种递归算法,用于搜索图或树数据结构的所有顶点。遍历意味着访问图的所有节点。

1. 深度优先搜索算法

    标准的DFS实现将图的每个顶点分为两类:

  1. 访问过
  2. 未访问过

    该算法的目的是在避免循环的同时将每个顶点标记为已访问。
    DFS算法的工作原理如下:

  1. 首先将图的任意一个顶点放在堆栈的顶部。
  2. 获取堆栈的顶部数据项并将其添加到已访问列表。
  3. 创建该顶点相邻节点的列表。将不在访问列表中的那些添加到堆栈顶部。
  4. 重复步骤2和3,直到堆栈为空。
2. 深度优先搜索图例

    让我们通过一个例子来看看深度优先搜索算法是如何工作的。我们使用1个有5个顶点的无向图。
在这里插入图片描述
    我们从顶点0开始,DFS算法首先把它放在访问列表中,然后把所有相邻的顶点放在堆栈中。
在这里插入图片描述
    接下来,我们访问堆栈顶部的元素,即1,并转到它的相邻节点。因为已经访问了0,所以我们改为访问2。
在这里插入图片描述
    顶点2有一个未访问的相邻顶点4,因此我们将其添加到堆栈顶部并访问它。
在这里插入图片描述
在这里插入图片描述
    在我们访问最后一个元素3之后,它没有任何未访问的相邻节点,因此我们完成了图的深度优先遍历。
在这里插入图片描述

3. DFS伪代码(递归实现)

    DFS的伪代码如下所示。在 init() 函数中,注意我们在每个节点上运行DFS函数。这是因为图可能有两个不同的断开部分,所以为了确保覆盖每个顶点,我们可以在每个节点上运行DFS算法。

DFS(G, u)
    u.visited = true
    for each v ∈ G.Adj[u]
        if v.visited == false
            DFS(G,v)
     
init() {
    
    
    For each u ∈ G
        u.visited = false
     For each u ∈ G
       DFS(G, u)
}
4. C示例

    深度优先搜索算法的代码和示例如下所示。代码被简化了,这样我们就可以专注于算法而不是其他细节。

// DFS algorithm in C

#include <stdio.h>
#include <stdlib.h>

struct node {
    
    
  int vertex;
  struct node* next;
};

struct node* createNode(int v);

struct Graph {
    
    
  int numVertices;
  int* visited;

  // We need int** to store a two dimensional array.
  // Similary, we need struct node** to store an array of Linked lists
  struct node** adjLists;
};

// DFS algo
void DFS(struct Graph* graph, int vertex) {
    
    
  struct node* adjList = graph->adjLists[vertex];
  struct node* temp = adjList;

  graph->visited[vertex] = 1;
  printf("Visited %d \n", vertex);

  while (temp != NULL) {
    
    
    int connectedVertex = temp->vertex;

    if (graph->visited[connectedVertex] == 0) {
    
    
      DFS(graph, connectedVertex);
    }
    temp = temp->next;
  }
}

// Create a node
struct node* createNode(int v) {
    
    
  struct node* newNode = malloc(sizeof(struct node));
  newNode->vertex = v;
  newNode->next = NULL;
  return newNode;
}

// Create graph
struct Graph* createGraph(int vertices) {
    
    
  struct Graph* graph = malloc(sizeof(struct Graph));
  graph->numVertices = vertices;

  graph->adjLists = malloc(vertices * sizeof(struct node*));

  graph->visited = malloc(vertices * sizeof(int));

  int i;
  for (i = 0; i < vertices; i++) {
    
    
    graph->adjLists[i] = NULL;
    graph->visited[i] = 0;
  }
  return graph;
}

// Add edge
void addEdge(struct Graph* graph, int src, int dest) {
    
    
  // Add edge from src to dest
  struct node* newNode = createNode(dest);
  newNode->next = graph->adjLists[src];
  graph->adjLists[src] = newNode;

  // Add edge from dest to src
  newNode = createNode(src);
  newNode->next = graph->adjLists[dest];
  graph->adjLists[dest] = newNode;
}

// Print the graph
void printGraph(struct Graph* graph) {
    
    
  int v;
  for (v = 0; v < graph->numVertices; v++) {
    
    
    struct node* temp = graph->adjLists[v];
    printf("\n Adjacency list of vertex %d\n ", v);
    while (temp) {
    
    
      printf("%d -> ", temp->vertex);
      temp = temp->next;
    }
    printf("\n");
  }
}

int main() {
    
    
  struct Graph* graph = createGraph(4);
  addEdge(graph, 0, 1);
  addEdge(graph, 0, 2);
  addEdge(graph, 1, 2);
  addEdge(graph, 2, 3);

  printGraph(graph);

  DFS(graph, 2);

  return 0;
}
5. 深度优先搜索的复杂性

    DFS算法的时间复杂度用O(V+E)表示,其中V是节点数,E是边数。
    算法的空间复杂度为O(V)。

6. DFS算法的应用
  1. 寻找路径
  2. 测试图是否为二部图
  3. 用于查找图的强连接组件
  4. 用于检测图中的循环
参考文档

[1]Parewa Labs Pvt. Ltd.Depth First Search (DFS)[EB/OL].https://www.programiz.com/dsa/graph-dfs,2020-01-01.

猜你喜欢

转载自blog.csdn.net/zsx0728/article/details/114640856