数据结构与算法(bfs与dfs)

引言:经过上一次的学习,我们明白了图的基本操作。这一次,我们学习图的两种基本算法——bfs与dfs。

图的遍历

1.dfs算法

介绍:dfs算法也叫深度优先搜索,核心思想是从某一位置或者状态出发,进行搜索,直到找到为止。形象的可以认为是所有的可能都走一边,既暴力。
深度优先遍历图的方法是,从图中某顶点v出发:
(1)访问顶点v;
(2)依次从v的未被访问的邻接点出发,对图进行深度优先遍历;直至图中和v有路径相通的顶点都被访问;
(3)若此时图中尚有顶点未被访问,则从一个未被访问的顶点出发,重新进行深度优先遍历,直到图中所有顶点均被访问过为止。

(一)dfs模板

void dfs(写入的参数) 
{
	if(条件符合要求)
	{
		进行相关的操作(比如输出,计数等)
		return ;//结束操作 
	}
	循环遍历每一种可能,进行相关的操作
	{
		if(这种方式没有进行)
		{
			标记; 
			进行;
			dfs(参数改变);
			回溯; 
		} 
	} 
	 
}

(二)例题

下面给出一道相关的例题:
排列数字

给定一个整数n,将数字1~n排成一排,将会有很多种排列方法。
现在,请你按照字典序将所有的排列方法输出。
Input
共一行,包含一个整数n。
Output
按字典序输出所有排列方案,每个方案占一行。
Input
3
Output
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
这道题我们就可以使用dfs算法来完成:

#include <iostream>
#include <algorithm>
#include <stack>
using namespace std;
const int N=1e5+3;
int n,m,j,k,l;
int s[N];
bool st[N];
void dfs(int k)
{
    if(k==n)
    {
        for(int i=0;i<n;i++)
        cout<<s[i]<<" ";
        puts("");
        return ;
    }
    for(int i=1;i<=n;i++)
    {
        if(st[i]==false)
        {
            s[k]=i;
            st[i]=true;
            dfs(k+1);
            st[i]=false;
        }
    }
}
int main()
{
    cin>>n;
    dfs(0);//从0开始遍历
    return 0;
}

2.bfs算法

简介:bfs又叫广度优先搜索,主要使用队列来完成某些操作
广度优先搜索使用队列来实现,整个过程也可以看做一个倒立的树形:
1、把根节点放到队列的末尾。
2、每次从队列的头部取出一个元素,查看这个元素所有的下一级元素,把它们放到队列的末尾。并把这个元素记为它下一级元素的前驱。
3、找到所要找的元素时结束程序。
4、如果遍历整个树还没有找到,结束程序。

(一)bfs模板

注:模板不一定唯一

#include <queue>//这里我们使用STL 
const int N=103;
int st[N][N]={0};
typedef struct node 
{
	int x;
	int y;
}list;//定义结构体,用来存放点或者其他 
//定义方向数组 
int dx[4]={1,0,-1,0};
int dy[4]={0,-1,0,1};
queue<list>q;//定义队列
void bfs(参数)
{
	list s;
	st[0][0]=1;
	q.push(list p);
	while(!q.empty())
	{
		s=q.front();
		q.pop();
		for(int i=0;i<4;i++)
		{
			int a=s.x+dx[i];
			int b=s.y+dy[i];
			if(条件如果成立)
			{
				list ss;
				ss.x=a;
				ss.y=b;
				q.push(ss);
				st[a][b]=st[s.x][s.y]+1;
			}
		}
	}
	进行最后的相关操作; 
} 

(二)例题

走迷宫
给定一个n*m的二维整数数组,用来表示一个迷宫,数组中只包含0或1,其中0表示可以走的路,1表示不可通过的墙壁。
最初,有一个人位于左上角(1, 1)处,已知该人每次可以向上、下、左、右任意一个方向移动一个位置。
请问,该人从左上角移动至右下角(n, m)处,至少需要移动多少次。
数据保证(1, 1)处和(n, m)处的数字为0,且一定至少存在一条通路。
Input
第一行包含两个整数n和m。
接下来n行,每行包含m个整数(0或1),表示完整的二维数组迷宫。
Output
输出一个整数,表示从左上角移动至右下角的最少移动次数。
Input
5 5
0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
Output
8

#include <iostream>
#include <algorithm>
#include <queue>
#include <string.h>
using namespace std;
const int N=103;
typedef pair<int,int> pii;
int n,m;
int a[N][N],b[N][N];
void bfs()
{
	memset(b,-1,sizeof(b));
	b[0][0]=0;
	queue<pii> q;
	q.push({0,0});
	int dx[]={0,1,0,-1},dy[]={1,0,-1,0};
	while(!q.empty())
	{
		pii t=q.front();
		q.pop();
		for(int i=0;i<4;i++)
		{
			int x=dx[i]+t.first;
			int y=dy[i]+t.second;
			if(x<0||y<0||x>=n||y>=m||b[x][y]!=-1||a[x][y]!=0)
			{
				continue;
			}
			q.push({x,y});
			b[x][y]=b[t.first][t.second]+1;
		}
	}
	cout<<b[n-1][m-1]<<endl;
}
int main()
{
	
	cin>>n>>m;
	for(int i=0;i<n;i++)
	for(int j=0;j<m;j++)
	{
		cin>>a[i][j];
	}
	bfs();
	return 0;
}

后记

学习这两算法时候,确实耗费了不少时间与精力。每每回想过去一点点的进步,便有了继续下去的动力。数据结构部分可以说是告一段落了,下次就是算法部分。希望大家可以给出更好的意见。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风送雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值