什么是搜索
在学习深度优先搜索和广度优先搜索之前,我们先了解一下什么是搜索
搜索其实就是一个通过不同的试探去找寻我们所需要的解的一种方法,什么是不同的试探呢?不同的试探就是尝试不同的路径直到找到我们所需要的那条路径。
搜索的分类
搜索的分类是非常之多
最基础的有:暴力的搜索、深搜(深度优先搜索|DFS)、广搜(广度优先搜索|BFS)
高级的有:IDDFS(迭代加深搜索(深搜的一种))、DBFS(双向广搜)、A*(一种启发式搜索,需要写估价函数)、IDA*(迭代加深+全局最优性)等等
深搜(深度优先搜索|DFS)
深搜的思路
对于深搜的描述有这样两句话:
“一条路走到黑”
“走不了了再倒回来”
也就是说,深搜的搜索方式,在每次遇到可以选择多个方向时,总是按照有一种选择顺序,比如先选往上走,走不通再倒回来往左走,再走不通又倒回来往后下走,还走不通又倒回来往右走。当然,我只是这样举个例子,实际如何选择走的方向可能会因题而异。每当它选择一个方向后,它总会先把这个方向上的所以可能性探索完,不行再回溯到刚刚分叉的地方,换一个方向继续。如此一整个过程便是深搜的思路。
我们根据这样的思路可以大致写一个伪代码
void dfs(当前状态)
{
//判断当前状态是否合法(什么叫是否合法呢?比如一个数组,如果我们当前状态所使用的坐标已经越界了,那这个状态肯定是不合法的)
//如何当前状态合法,那么我们又可以调用dfs(把下一个状态传进去)
//如果当前状态不合法,那我们就需要回溯,即返回到上一次的状态
}
int main()
{
...
...
dfs(传入初始状态)
...
...
}
广搜(广度优先搜索|BFS)
广搜的思路
广搜就是从起点一层一层的往外扩散,直到遇到目标为止。就像水花一个,一圈一圈的从中心往外扩散
举个例子
//#是障碍物
//E是空地
那么我们假设起点A,终点是B
我们有一张这样的地图
A#EB 那我们可以把它抽象为
E#EE
E#E#
EEEE
搜索的存储
如果是一张地图,那么它将会是一个二维的平面,那我们就需要用一个二维数组来存储
补充知识
1.实现全排列(next_permutation)
next_permutation函数的头文件
#include<algorithm>
next_permutation函数的用法
next_permutation函数一般是搭配do while使用的,其使用格式一般是这样
a[n]={1, 2, 3, ... , n};//一个已经排好序了的数组
do{
//以输出全排列为例
for(int i=0;i<n;i++)
{
printf("%d ", a[i]);
}
printf("\n");
}while(next_permutation(a, a+n));
next_permutation函数,其意为下一个排列,即譬如我们给了一个1 2 3,对于1到3的全排列它是这样的:
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
所以1 2 3的下一个排列是1 3 2;如果对1 2 3调用了next_permutation函数那么其结果将是1 3 2
实现全排列的代码
在知道next_permutation函数的用法后,我们可以像这样来实现全排列
#include<stdio.h>
#include<algorithm>
using namespace std;
int main()
{
int a[3]={1, 3, 2};
sort(a, a+3); //在需要实现全排列的数组没有排序的时候,我们需要先对它进行升序排序,即从小到大排
do{
for(int i=0;i<3;i++)
{
printf("%d ", a[i]);
}
printf("\n");
}while(next_permutation(a, a+3));
return 0;
}
这样我们就实现了1到3的全排列,当我们需要把这些全排列的结果存储起来的时候,我们可能开数组去存,不过内存占用会很大。
全排列练习题
牛客:NC15128老子的全排列呢
2.双端队列
什么是双端队列,就像他的名字一样,这种容器可以在头和尾都进行压入和弹出(即,插入和删除),除了插入删除以外,双端队列的头和尾都可以被访问
双端队列的声明
deque<int> de; 注意:双端队列的头文件是 #include<deque>
deque的常用函数
de.push_front(); 从头插入元素
de.push_back(); 从尾插入元素
de.pop_front(); 删除队首元素
de.pop_back(); 删除队尾元素
de.front(); 访问队首元素
de.back(); 访问队尾元素
!de.empty(); 双端队列不为空
de.size(); 返回双端队列的长度
de.clear(); 清空双端队列
同时双端队列还支持 reverse、sort等函数,其用法如下
reverse(de.begin(), de.end());
sort(de.begin(), de.end());
双端队列的遍历
其遍历方法就和数组一样
#include<stdio.h>
#include<deque>
using namespace std;
deque<int> de;
int main()
{
de.push_front(3);
de.push_back(2);
for(int i=0;i<de.size();i++)
{
printf("%d ", de[i]);
}
return 0;
}