深度优先搜索DFS和广度优先搜索BFS
程序员文章站
2022-07-13 08:33:54
...
DFS——不断回溯的过程。
类似于树的先序遍历,从任一未被遍历过的点开始,将改点标记为visited,然后去找改点连通的点,如果没有被遍历则标记为visited,然后继续探索。。。。当没有可以探索的点时,则回溯到上一个点。
以上图为例,遍历过程为:v1 v2 v4 v 8 v 5 v3 v6 v7
注意:DFS结果不是唯一的,看自己是如何设定的,以下也可以使DFS遍历的结果
v1 v3 v7 v6 v2 v5 v8 v4
int MGraph::FirstAdj(int i){//找到第一个没有被visited的邻近点
for (int j =0; j < this->vexnum; j++){
if (this->visited[j] == false && this->arcs_matrix[i][j] != 0)
return j;
}
return -1;
}
int MGraph::NextAdj(int i,int w){//下一个没有被visited的邻近点
for (int j = w+1; j < this->vexnum; j++){
if (this->visited[j] == false && this->arcs_matrix[i][j] != 0)
return j;
}
return -1;
}
void MGraph::DFS(int i){
visited[i] = true;
cout << vexs[i] << " ";
for (int w = FirstAdj(i); w >= 0; w = NextAdj(i,w)){
DFS(w);
}
}
void MGraph::DFSTraverse(){
cout << "深度优先遍历" << endl;
for (int i = 0; i < this->vexnum; i++){//针对非连通图,如果是连通图一次DFS则可以
//全部遍历完
if (visited[i] == false)//false表示没有被visited
DFS(i);
}
//this->reset();复位是否visited
cout << endl;
}
DFS是一个不断回溯的过程,递归的方法本质上是系统帮我们实现了压栈出栈的过程,一切的递归过程都可以改为非递归。所以我们也可以用手动的压栈出栈。
仍然以上图为例:
手动压栈主要分为以下四个过程
注意:(文中所有的连通,都包括没有被visited这一条件)
从v1开始将v1压栈
访问栈顶v1,标记为visited,查找v1连通的点
找到v2 入栈
访问栈顶v2 标记为visited 查找v2连通的点
找到v4入栈
访问栈顶v4 标记为visited 查找v4连通的点
。。。。
最终访问完v1v2v4v8v5 栈中成员如上图1所示
开始回溯
栈顶v5 没有连通的点 出栈
栈顶v8 没有连通的点 出栈
。。。。。
最终栈中如图2所示
访问栈顶v1 找到v3
压栈。。。
最后结过如图3所示
再回溯 依次出栈 栈空 结束!
BFS
类似于树的层次遍历,通过队列实现。从任一未被visited的点开始,将其放入队列。
while(队列非空){
出队,标记为visited;
找到出队元素连通的点,入队 ;
}
void MGraph::BFSTraverse(){
cout << "广度优先遍历" << endl;
queue<int>q;//注意这里队列中记录是元素的下标
for (int i = 0; i < this->vexnum; i++){
if (visited[i] == false)
q.push(i);
while (!q.empty())
{
int temp = q.front();
q.pop();
if (visited[temp] == false){//加这一步判断是因为
//如果一个结点和多个结点连通,这个结点可能会被多次放入队列中
visited[temp] = true;
cout << vexs[temp] << " ";
}
for (int w = FirstAdj(temp); w >= 0; w = NextAdj(temp, w)){
q.push(w);
}
}
}
//this->reset();
cout << endl;
}