DFS(深度优先搜索 Depth First Search)
白话理解:
我觉得其实就是暴力把所有的路径都搜索出来,运用回溯,保存这次的位置,深入搜索,都搜索完了便回溯回来,搜下一个位置,直到把所有最深位置都搜一遍,要注意的一点是,搜索的时候有记录走过的位置,标记完后可能要改回来;
我的最白的理解就是,一个人每条路都一直走到黑,到头了再返回来,全走一遍,找出你想要的路。
回溯法:
回溯法是一种搜索法,按条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法;
图解:
例如这张图,从1开始到2,之后到5,5不能再走了,退回2,到6,退回2退回1,到3,一直进行;
理解这种方法比较简单,难的是要怎么用
伪代码理解:
简单来说就是这样:
void dfs() { 访问过的点 = 1; cout << " " << a; for (int i = 0; i < N; i++) { if (其他点到这个点有边并且该点未被访问过) // 该点未访问过并且其他点到这个点有边 { // Dfs递归 dfs(); } } }
详细来说:
void dfs(int deep) { int x=deep/n,y=deep%n; // 回溯结束判断条件 if(符合某种要求||已经不能在搜了) { 做一些处理操作; return ; } // 判断当前回溯结点是否满足条件,或者处理数据 // 这里可能会有多种条件,可能要循环什么的 if(符合某种条件且有地方可以继续搜索的) { a[x][y]='x'; // 可能要改变条件,这个是瞎写的 dfs(deep+1,sum+1); // 搜索下一层 a[x][y]='.'; // 可能要改回条件,有些可能不用改比如搜地图上有多少块连续的东西 } // 最后可能要判断一些特殊条件,处理一些特殊数据,一般没有 }
BFS(宽度/广度优先搜索 Breadth First Search)
白话理解:
我觉得就是从某点开始,走四面可以走的路,然后在从这些路,在找可以走的路,直到最先找到符合条件的,这个运用需要用到队列(queue)。
我的最白的理解就是,一群人(无数),碰到了一个岔路,就派出去一队人继续走,遇到岔路再分,让人们一次性的遍布整个图,最后找出你想要的路。
图解:
还是这张图,从1开始搜,有2,3,4几个点,存起来,从2开始有5,6,存起来,搜3,有7,8,存起来,搜4,没有了;现在开始搜刚刚存的点,从5开始,没有,然后搜6…一直进行,直到找到;
伪代码理解:
简单来说
void bfs() { 创建队列 将点压入队列; 访问过该点 = 1; while (队列不为空) { 设an为队首元素; 弹出队首元素; 将an输出; for (int i = 0; i < N; i++) { if (该点未访问过并且该点与其他点有边) { 标记该点为1,被访问过 将该点压入队列 } } } }
详细来说(当然,也不是每个都这样写):
int visit[N][N]// 用来记录走过的位置 int dir[4][2]={ 0,-1, 0,1, -1,0, 1,0 }; // 上下左右四个方向 struct node { int x,y,bits; // 一般是点,还有步数,也可以存其他的 ...... }; queue<node>v; void bfs(node p) { node t,tt; v.push(p); while(!v.empty()) { t=v.front();// 取出最前面的 v.pop(); // 删除 // 终止判断 if(找到符合条件的) { 做记录; while(!v.empty()) // 如果后面还需要用,随手清空队列 v.pop(); return; } visit[t.x][t.y]=1; // 走过的进行标记,以免重复 { tt=t; tt.x+=dir[i][0]; tt.y+=dir[i][1]; // 这里的是按照:向上下左右查找的 if(如果这个位置符合条件) { tt.bits++; // 步数加一 v.push(tt); // 把它推入队列,在后面的时候就可以用了 } } } }
DFS和BFS的区别
总结
bfs是浪费空间节省时间,dfs是浪费时间节省空间。
- 数据结构:
DFS用递归的形式,用到了栈结构,先进后出。
BFS选取状态用队列的形式,先进先出。
- 复杂度
DFS的复杂度与BFS的复杂度大体一致(O(∣V∣2)),不同之处在于遍历的方式与对于问题的解决出发点不同,DFS适合目标明确,而BFS适合大范围的寻找。
- 思想
思想上来说这两种方法都是穷竭列举所有的情况。