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;
}
