DFS&BFS算法总结
图论:
图的搜索是说在给定一些点,这些点之间存在某种关系,按照这种关系,构造成一个图。从一个起始点出发,把所有和这个点存在这种关系的点全部找出来的过程就是搜索。
BFS– 广度优先搜索BFS在访问了起始顶点A之后,由A出发,依次访问A的各个未被访问过的邻接顶点B,D,…, C, 然后再顺序访问B,D, …, C 的所有还未被访问过的邻接顶点。再从这些访问过的顶点出发,再访问它们的所有还未被访问过的邻接顶点,…如此做下去,直到图中所有顶点都被访问到为止。广度优先搜索是一种分层的搜索过程,每向前走一步可能访问一批顶点。
void BFS(){
int queue[N];//按照顺序储存被处理的点
int parent[N];//记录被处理的点的父亲节点
int top;
int i, j, k;
top = 0;
queue[top++] = 初始点;
parent[初始点] = -1;
标记初始点;
for(i = 0; i < top; i++){ //队列中还有未处理点
j = 队列中下一个处理点;
for(j的所有邻接点){
if(该邻接点未被标记){
queue[top++] = 邻接点;
parent[邻接点] = j;
标记该邻接点;
}
}
}
//此时队列中的点就是所有要找的点
}
BFS 的另一种应用
假设图的每条边的权值都是1,因为BFS是分层进行的,所以,从起点到达同一层点的路经距离应该是相同的,如果在图中标记一个起点和一个终点,从起点出发,用BFS逐层向终点靠近,那么当到达终点时,会形成一条路径,那么这条路径必定是这两点的最短路经。
BFS求最短路径
int BFS(){
NODEqueue[N];
int top;
inti, j,k;
top = 0;
queue[top].ind = 初始点;
queue[top++].level = 0;
标记初始点;
for(i = 0;i <top; i++){//队列中还有未处理点
j = 队列中下一个处理点;
for(j的所有邻接点){
if(该邻接点为被标记){
queue[top].ind = 邻接点;
queue[top++].level = queue[i].level + 1;
if(该邻接点== 终点)
returnqueue[i].level + 1;
标记该邻接点;
}
}
}
return -1;
}
其中
typedefstruct{
intind;
int level;
} NODE;
DFS– 深度优先搜索
DFS 在访问图中某一起始顶点A后,由A出发,访问它的任一邻接顶点B;再从B出发,访问与B邻接但还没有访问过的顶点E;然后再从E出发,进行类似的访问,… 如此进行下去,直至到达所有的邻接顶点都被访问过的顶点G为止。接着, 退回一步, 退到前一次刚访问过的顶点,看是否还有其它没有被访问的邻接顶点。如果有,则访问此顶点,之后再从此顶点出发,进行与前述类似的访问;如果没有,就再退回一步进行搜索。重复上述过程,直到连通图中所有顶点都被访问过为止。
BFS 与 DFS 的比较可以看到,广度优先搜索是按层次来搜索的,根据第一层遍历出第二层,当第二层全部被访问完之后,再处理第二层,由第二层访问到第三层,依次类推,直到处理完最后一层。
深度优先搜索是运用堆栈,从第一层的一个点,递归到第二层的一个点,再递归到第三层,到最后一层后,在回溯到上一层,然后从上一层递归到它的下一层的另一个点,直到它的所有点都被访问完,再回溯到上一层,依此类推,直到回溯到起点,这时所有的点都被访问完,最后形成一棵树的形状。
我们可以把BFS 形象地当作是水波的扩散,而DFS
则是顺藤摸瓜.
DFS 代码分析void DFS( Point P ){
每次递归到一个点,则检查是否存在与它相邻,而且未被访问的点,有则递归访问这个点,无则返回上一层。
inti;
for(所有P的邻接点K){//每次递归到一个点,则检查是否存在与它相邻,而且未被访问的点,有则递归访问这个点,无则返回上一层。
if(K未被访问){
标记K;
DFS(K);
}
}
}
DFS& BFS
这两种搜索方法除了可以用来遍历图以外,也常用来搜索各种状态,最常见的就是用来搜索最优值,或者搜索某种状态是否存在等等。
深度优先搜索的做法是:每递归到一层,则改变这一层的状态,之后递归到下一层,下一层同样改变它那一层的状态,递归到再下一层,当递归到最后一层时,每层的状态会形成一个最终的状态,我们需要将这个状态与得到的其他状态作比较,保留其中较优的一个。
当某一层的所有状态都被改变过一次后,回溯到上一层。每层都作类似的操作,最后所有的状态都会被搜索到,我们最后保留的较优值就是要求的最优值。
DFS代码分析
void DFS( int depth ){
inti;
if (depth > n){
if (搜索到结果) 比较并记录;
return;
}
else{
for(所有状态)
if (符合递归条件){
标记状态;
dfs(depth + 1 );
回溯;
}
}
}
可以看到,这样的搜索,时间复杂度是(a^n)的,a为每次的状态数,n为总的递归层数。
这个复杂度属于指数复杂度,当n比较大时,很荣易超时,所以,一般在n比较小的时候有深搜。
而且很多情况下需要剪枝。