C语言需要掌握的基础知识点之DFS(深度优先搜索)

C语言需要掌握的基础知识点之DFS(深度优先搜索)

在C语言中,DFS(深度优先搜索)是一种重要的图遍历算法,也可以应用于树结构。以下是DFS的详细讲解:

DFS基本概念

深度优先搜索:沿着树的深度遍历节点,尽可能深地搜索树的分支。当节点v的所在边都已被探寻过,搜索将回溯到发现节点v的那条边的起始节点。

图的表示

邻接矩阵表示

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#define MAX 100

int graph[MAX][MAX];  // 邻接矩阵
int visited[MAX];     // 访问标记数组
int n;               // 顶点数

// 初始化图
void initializeGraph() {
    for(int i = 0; i < MAX; i++) {
        visited[i] = 0;
        for(int j = 0; j < MAX; j++) {
            graph[i][j] = 0;
        }
    }
}

邻接表表示

c 复制代码
typedef struct Node {
    int vertex;
    struct Node* next;
} Node;

typedef struct Graph {
    int numVertices;
    Node** adjLists;
    int* visited;
} Graph;

// 创建节点
Node* createNode(int v) {
    Node* newNode = (Node*)malloc(sizeof(Node));
    newNode->vertex = v;
    newNode->next = NULL;
    return newNode;
}

// 创建图
Graph* createGraph(int vertices) {
    Graph* graph = (Graph*)malloc(sizeof(Graph));
    graph->numVertices = vertices;
    
    graph->adjLists = (Node**)malloc(vertices * sizeof(Node*));
    graph->visited = (int*)malloc(vertices * sizeof(int));
    
    for(int i = 0; i < vertices; i++) {
        graph->adjLists[i] = NULL;
        graph->visited[i] = 0;
    }
    return graph;
}

// 添加边
void addEdge(Graph* graph, int src, int dest) {
    // 添加从src到dest的边
    Node* newNode = createNode(dest);
    newNode->next = graph->adjLists[src];
    graph->adjLists[src] = newNode;
    
    // 对于无向图,添加从dest到src的边
    newNode = createNode(src);
    newNode->next = graph->adjLists[dest];
    graph->adjLists[dest] = newNode;
}

DFS递归实现

基于邻接矩阵的DFS

c 复制代码
// 递归DFS
void DFS_Matrix(int v) {
    visited[v] = 1;
    printf("%d ", v);
    
    for(int i = 0; i < n; i++) {
        if(graph[v][i] == 1 && !visited[i]) {
            DFS_Matrix(i);
        }
    }
}

基于邻接表的DFS

c 复制代码
void DFS_List(Graph* graph, int vertex) {
    Node* adjList = graph->adjLists[vertex];
    Node* temp = adjList;
    
    graph->visited[vertex] = 1;
    printf("%d ", vertex);
    
    while(temp != NULL) {
        int connectedVertex = temp->vertex;
        
        if(graph->visited[connectedVertex] == 0) {
            DFS_List(graph, connectedVertex);
        }
        temp = temp->next;
    }
}

DFS非递归实现(使用栈)

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#define MAX 100

// 栈结构
typedef struct Stack {
    int arr[MAX];
    int top;
} Stack;

// 栈操作
void initStack(Stack* s) {
    s->top = -1;
}

int isEmpty(Stack* s) {
    return s->top == -1;
}

void push(Stack* s, int value) {
    if(s->top < MAX - 1) {
        s->arr[++(s->top)] = value;
    }
}

int pop(Stack* s) {
    if(!isEmpty(s)) {
        return s->arr[(s->top)--];
    }
    return -1;
}

// 非递归DFS
void DFS_Iterative(int graph[MAX][MAX], int start, int n) {
    int visited[MAX] = {0};
    Stack s;
    initStack(&s);
    
    push(&s, start);
    visited[start] = 1;
    
    printf("DFS遍历顺序: ");
    
    while(!isEmpty(&s)) {
        int current = pop(&s);
        printf("%d ", current);
        
        // 将所有未访问的邻接点入栈
        for(int i = n - 1; i >= 0; i--) {
            if(graph[current][i] == 1 && !visited[i]) {
                push(&s, i);
                visited[i] = 1;
            }
        }
    }
    printf("\n");
}

完整的DFS示例程序

c 复制代码
#include <stdio.h>
#include <stdlib.h>

#define MAX 100

int graph[MAX][MAX];
int visited[MAX];
int n;

// 初始化
void initialize() {
    for(int i = 0; i < MAX; i++) {
        visited[i] = 0;
        for(int j = 0; j < MAX; j++) {
            graph[i][j] = 0;
        }
    }
}

// 添加边
void addEdge(int u, int v) {
    graph[u][v] = 1;
    graph[v][u] = 1; // 无向图
}

// 递归DFS
void DFS(int v) {
    visited[v] = 1;
    printf("%d ", v);
    
    for(int i = 0; i < n; i++) {
        if(graph[v][i] == 1 && !visited[i]) {
            DFS(i);
        }
    }
}

// 非递归DFS
void DFS_NonRecursive(int start) {
    int stack[MAX];
    int top = -1;
    int visited2[MAX] = {0};
    
    stack[++top] = start;
    visited2[start] = 1;
    
    printf("非递归DFS: ");
    
    while(top != -1) {
        int current = stack[top--];
        printf("%d ", current);
        
        for(int i = n - 1; i >= 0; i--) {
            if(graph[current][i] == 1 && !visited2[i]) {
                stack[++top] = i;
                visited2[i] = 1;
            }
        }
    }
    printf("\n");
}

int main() {
    initialize();
    
    n = 6; // 顶点数
    
    // 添加边
    addEdge(0, 1);
    addEdge(0, 2);
    addEdge(1, 3);
    addEdge(1, 4);
    addEdge(2, 5);
    addEdge(3, 4);
    
    printf("递归DFS遍历顺序: ");
    DFS(0);
    printf("\n");
    
    DFS_NonRecursive(0);
    
    return 0;
}

DFS的应用

连通分量计数

c 复制代码
// 计算连通分量数量
int countConnectedComponents() {
    int count = 0;
    for(int i = 0; i < n; i++) {
        if(!visited[i]) {
            DFS(i);
            count++;
        }
    }
    return count;
}

路径查找

c 复制代码
// 查找从start到end的路径
int path[MAX], pathIndex = 0;

int findPath(int start, int end, int current) {
    visited[current] = 1;
    path[pathIndex++] = current;
    
    if(current == end) {
        return 1; // 找到路径
    }
    
    for(int i = 0; i < n; i++) {
        if(graph[current][i] == 1 && !visited[i]) {
            if(findPath(start, end, i)) {
                return 1;
            }
        }
    }
    
    pathIndex--; // 回溯
    return 0;
}

检测环

c 复制代码
// 检测无向图中是否存在环
int hasCycle(int v, int parent) {
    visited[v] = 1;
    
    for(int i = 0; i < n; i++) {
        if(graph[v][i] == 1) {
            if(!visited[i]) {
                if(hasCycle(i, v)) {
                    return 1;
                }
            } else if(i != parent) {
                return 1;
            }
        }
    }
    return 0;
}
相关推荐
序属秋秋秋7 小时前
《Linux系统编程之进程控制》【进程等待】
linux·c语言·c++·进程·系统编程·进程控制·进程等待
lingran__9 小时前
C语言自定义类型详解 (1.1w字版)
c语言·开发语言
一路往蓝-Anbo13 小时前
C语言从句柄到对象 (一) —— 全局变量的噩梦与“多实例”的救赎
c语言·开发语言·stm32·单片机·嵌入式硬件·物联网
松涛和鸣13 小时前
DAY42 SQLite3 : Dictionary Import and Data Query Implementation with C Language
linux·c语言·数据库·单片机·网络协议·sqlite
水饺编程14 小时前
Visual Studio 软件操作:添加附加依赖项
c语言·c++·windows·visual studio
一路往蓝-Anbo14 小时前
C语言从句柄到对象 (三) —— 抛弃 Malloc:静态对象池与索引句柄的终极形态
c语言·开发语言·数据结构·stm32·单片机·算法
序属秋秋秋15 小时前
《Linux系统编程之进程控制》【进程创建 + 进程终止】
linux·c语言·c++·操作系统·进程·进程创建·进程终止
一路往蓝-Anbo15 小时前
C语言从句柄到对象 (二) —— 极致的封装:不透明指针与 SDK 级设计
c语言·开发语言·数据结构·stm32·单片机·嵌入式硬件
上天_去_做颗惺星 EVE_BLUE15 小时前
C++学习:学生成绩管理系统
c语言·开发语言·数据结构·c++·学习
水饺编程15 小时前
开源项目介绍:VirtuaNES 模拟器
c语言·c++·windows·visual studio