c++:DFS与BFS详解

本文详细介绍了深度优先搜索(DFS)与宽度优先搜索(BFS)两种算法的基本原理及应用实例。通过具体案例,展示了如何使用DFS解决状态遍历问题,以及如何利用BFS寻找最短路径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

DFS(深度优先搜索):从某个状态开始,不断转移状态到无法转移为止,然后退回到前一步,继续转移到其他状态,不断重复,直至找到最终的解。

         总是从最开始的状态出发,遍历所有的可到达状态。隐式利用栈进行计算

eg:有一个N*M的田,雨后积水,八连通(下图相对w的*部分)的积水被认为连在一起,请给出园里有多少水洼?

      ***

      *w*

      ***

  input :3 3  

***

*w*

w**

 output: 1


  解析:从任意w开始,不停把w邻接部分用*代替,复杂度O(N*M)

int n, m;
char field[max_n][max_m+1];

//现在的位置
void dfs(int x, int y)
{
	field[x][y] = '*';
	for (int dx = -1; dx <= 1; dx++)
	{
		for (int dy = -1; dy <= 1; dy++)
		{
			int nx = x + dx, ny = y + dy;
			if (0 < nx&&nx < n && 0 < ny&&ny < m&&field[nx][ny] == 'W')
				dfs(nx, ny);

		}
	}
	return ;
}

void solve()
{
	int count = 0;
	for (int i = 0; i < n; i++)
	for (int j = 0; j < m; j++)
	if (field[n][m] == 'W')
	{
		dfs(i, j);
		count++;
	}
	printf("d%\n", count);
}

BFS(宽度优先搜索)总是先搜索距离初始状态近的状态,利用队列进行运算。复杂度O(状态数*转移的方式)

给定一个大小为N*M的迷宫,由通道('.')和墙壁('#')组成,其中通道S表示起点,通道G表示终点,每一步移动可以达到上下左右中不是墙壁的位置。试求出起点到终点的最小步数。(本题假定迷宫是有解的)(N,M<=100)

样例输入:

10 10

样例输出:

22


解析:bfs中,对于已经访问过得状态用标记管理,本例用INF标记,并初始化d数组,这样到达终点就会终止搜索,可如果一直下去直到队列为空,就可以计算出各个地点的

最 短距离。

#include <iostream>
#include <queue>
using namespace std;
const int MAX_N = 100;
const int MAX_M = 100;
const int INF = 0x3f3f3f3f;
//用pair表示状态时,用typedef更方便一些
typedef pair<int, int> P;
char maze[MAX_N][MAX_M + 1];
int N, M;
int sx, sy; //起点的位置
int gx, gy; //终点的位置

int d[MAX_N][MAX_M];//储存起点到某一点的距离
int dx[4] = { 1,0,-1,0 }, dy[4] = { 0,1,0,-1 }; //表明每次x和y方向的位移

void bfs()
{
	queue<P> que;
	for (int i = 0; i < N; i++)
		for (int j = 0; j < M; j++)
			d[i][j] = INF;	//初始化所有点的距离为INF
	que.push(P(sx, sy));
	d[sx][sy] = 0;	//从起点出发将距离设为0,并放入队列首端

	while (que.size()) //题目保证有路到终点,所以不用担心死循环
	{
		P p = que.front(); que.pop();//弹出队首元素
		int i;
		for (i = 0; i < 4; i++)
		{
			int nx = p.first + dx[i];
			int ny = p.second + dy[i];//移动后的坐标
			//判断可移动且没到过
			if (0 <= nx&&nx < N
				&& 0 <= ny&&ny < M
				&&maze[nx][ny] != '#'
				&&d[nx][ny] == INF)//之前到过的话不用考虑,因为距离在队列中递增,肯定不会获得更好的解
			{
				que.push(P(nx, ny));	//可以移动则设定距离为之前加一,放入队列
				d[nx][ny] = d[p.first][p.second] + 1;
				if(nx==gx && ny==gy) break;

                        }
		}
		if(i!=4) break;
	}

}

int main()
{
	cin>>N>>M;
	for (int i = 0; i < N; i++)
		cin>>maze[i];
	for (int i = 0; i < N; i++)
		for (int j = 0; j < M; j++)
		{
			if (maze[i][j] == 'S')
			{
				sx = i; sy = j;
			}
			if (maze[i][j] == 'G')
			{
				gx = i; gy = j;
			}
		}
	bfs();
	cout<<d[gx][gy]<<endl;

	return 0;
}

总结:bfs与dfs两种都能生成所有遍历状态,但是要求对所有状态进行处理时使用dfs比较方便;在求最短路径用bfs比较好。

<think>好的,我现在需要帮助用户了解如何在C语言中实现深度优先搜索(DFS)算法。首先,我需要回忆DFS的基本概念工作原理。DFS是一种用于遍历或搜索树或图的算法,它会尽可能深地访问节点,直到没有未访问的邻居为止,然后回溯并继续探索其他分支。 用户提到了参考引用中的C语言递归实现,所以应该以递归方法为主。但要注意到引用[1]提到递归可能导致栈溢出,特别是处理大图时,可能需要使用显式栈。不过用户的问题明确要求C语言实现示例,所以先提供递归版本,再提到优化的迭代版本可能更好。 接下来,我需要整理实现DFS的关键步骤。首先,图的表示,通常有邻接矩阵或邻接表。引用[3]中的示例使用了邻接表,通过结构体NodeGraph来定义。因此,我应该按照类似的结构来构建示例代码。 然后,DFS函数需要递归地访问节点,标记已访问的节点,并遍历其邻居。引用[3]中的DFS函数使用了递归,每次访问一个节点后递归访问其未访问的邻居。需要注意避免循环访问,所以需要一个visited数组来记录访问状态。 另外,用户可能需要完整的代码示例,包括图的创建、初始化以及主函数的调用。因此,我需要确保代码示例包含这些部分,比如定义结构体、创建图的函数,以及主函数中调用DFS的流程。 还需要注意代码的注释可读性,方便用户理解每一步的作用。比如,在DFS函数中,输出访问的节点是为了演示遍历顺序,实际应用中可能需要其他操作。 同时,用户提供的引用中有提到Python实现的例子,但用户现在需要的是C语言,所以重点应放在C的语法结构上,比如指针的使用、动态内存分配等。需要确保代码中没有内存泄漏,比如在创建图的时候正确分配释放内存。 此外,用户可能遇到的问题包括递归深度过大导致的栈溢出,所以在注意事项中需要提到这一点,并建议对于大规模数据使用迭代方法。引用[1]中也提到了这一点,所以应该引用相关部分来说明。 最后,生成的相关问题需要围绕实现细节、优化方法应用场景展开,帮助用户进一步学习。比如如何优化DFS,如何处理栈溢出,DFS的应用案例等。</think>### C语言实现深度优先搜索(DFS)算法 #### 1. 算法实现核心思路 深度优先搜索(DFS)通过递归或栈结构实现"纵向优先"的遍历策略,其核心逻辑为: 1. 访问起始顶点并标记为已访问 2. 递归访问当前顶点的未访问邻接顶点 3. 重复上述过程直至回溯到起始点[^2] #### 2. 完整代码实现(递归版本) ```c #include <stdio.h> #include <stdlib.h> // 邻接表节点结构 typedef struct Node { int vertex; struct Node* next; } Node; // 图结构 typedef struct { int numVertices; Node** adjList; } Graph; // 创建图 Graph* createGraph(int vertices) { Graph* graph = (Graph*)malloc(sizeof(Graph)); graph->numVertices = vertices; graph->adjList = (Node**)malloc(vertices * sizeof(Node*)); for (int i = 0; i < vertices; i++) { graph->adjList[i] = NULL; } return graph; } // 添加边(无向图) void addEdge(Graph* graph, int src, int dest) { // 添加src到dest的边 Node* newNode = (Node*)malloc(sizeof(Node)); newNode->vertex = dest; newNode->next = graph->adjList[src]; graph->adjList[src] = newNode; // 添加dest到src的边(无向图) newNode = (Node*)malloc(sizeof(Node)); newNode->vertex = src; newNode->next = graph->adjList[dest]; graph->adjList[dest] = newNode; } // DFS递归实现 void DFS(Graph* graph, int vertex, int* visited) { visited[vertex] = 1; printf("访问节点: %d\n", vertex); Node* temp = graph->adjList[vertex]; while (temp) { int adjVertex = temp->vertex; if (!visited[adjVertex]) { DFS(graph, adjVertex, visited); } temp = temp->next; } } int main() { Graph* graph = createGraph(5); addEdge(graph, 0, 1); addEdge(graph, 0, 2); addEdge(graph, 1, 3); addEdge(graph, 2, 4); int* visited = (int*)calloc(graph->numVertices, sizeof(int)); printf("DFS遍历顺序:\n"); DFS(graph, 0, visited); // 释放内存 free(visited); // 此处应添加释放图内存的代码(略) return 0; } ``` #### 3. 代码解析 1. **数据结构设计**: - `Node`结构体表示邻接表节点 - `Graph`结构体存储顶点数邻接表数组 - 使用动态内存分配实现灵活的数据结构[^3] 2. **算法流程**: - 初始化访问标记数组 - 递归访问顶点及其未访问邻居 - 采用先标记后访问的顺序保证正确性 3. **时间复杂度**: $$O(V + E)$$ 其中$V$为顶点数,$E$为边数 #### 4. 执行示例 ``` DFS遍历顺序: 访问节点: 0 访问节点: 1 访问节点: 3 访问节点: 2 访问节点: 4 ``` #### 5. 注意事项 1. 递归实现简单但存在栈溢出风险,当处理大规模数据时应改用栈结构迭代实现[^1] 2. 访问顺序取决于邻接表的构建方式(头插法) 3. 需注意内存管理,避免内存泄漏
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值