图的遍历(DFS、BFS)

深度优先遍历(DFS)

思想:

一条路走到底:走到访问过的结点,退回上一结点;从上一结点开始,继续遍历未访问的结点,重复此项工作。(遍历次序可能不同)
案例:根的先根遍历

代码(邻接矩阵)(连通图)

代码思想:每次取出一个元素,放入与该元素相连的并且没有放入栈中的其他结点;直到无路可走,只取栈中元素。

image


(伪)代码:

void DFS(AMGraph G,int v)//v起始顶点
{
    int Visited[AMGraph.vexnum];//辅助数组:记录节点有没有被访问过
    memset(Visited,0,sizeof(Visited));//0代表未访问过
   
    cout<<v ; Visited[v]=1;
    for(int w=0;w<G.vexnum;w++)
    {
        if(G.arcnum[v][w]!=0&&(!Visited[w]))
            DFS(G,w);
        //w是v的邻接点,如果w未访问,则递归调用DFS
    }
}

对于非连通图:遍历完一个连通分量后,再遍历另一个连通分量

代码(C++模拟邻接表)(连通图)

#include <bits/stdc++.h>
using namespace std;
const int Int = 2e5+5;
vector<int> graph[Int];//可变数组模拟邻接表
int visited[Int];//记录该点是否遍历过
int n,m;//n个顶点,m条边
void DFS(int key)
{
    cout<<key<<' ';
    visited[key]=1;

    int i;
    int len=graph[key].size();
    for(i=0; i<len; i++)
    {
        int o=graph[key][i];
        if(visited[o]==0)
        {
           DFS(o);
        }
    }
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
    memset(graph,0,sizeof(graph));//初始化
    memset(visited,0,sizeof(visited));//初始化
    cin>>n>>m;//n个顶点,m条边
    int i;
    int a,b;
    for(i=0; i<m; i++)
    {
        cin>>a>>b;
        graph[a].push_back(b);
        graph[b].push_back(a);
    }
    for(i=1; i<=n; i++)//从小到大排序
    {
        sort(graph[i].begin(),graph[i].end());
    }
    DFS(0);//从0开始遍历
    cout<<endl;
    }
    return 0;
}


实战

一. 模板题

#include <iostream>
#include <string.h>
using namespace std;

int visit[100];//记录结点有没有被访问过
int k,m;
int Map[100][100];//数据图
void DFS(int x)
{
    int j;
    for(j=0; j<k; j++)
    {
        if(visit[j]==0&&Map[x][j]==1)
            //找到当前节点下一个未被遍历且有边相连的节点//
        {
            visit[j]=1;
            cout<<" "<<j;
            DFS(j);
        }
    }


}

int main()
{
    int n;
    cin>>n;

    while(n--)
    {
        memset(Map,0,sizeof(Map));
        memset(visit,0,sizeof(visit));
        cin>>k>>m;
        int i;
        int u,v;
        for(i=0; i<m; i++)
        {
            cin>>u>>v;
            Map[v][u]=Map[u][v]=1;
            //这是无向图别忘了对称位置也要赋值
        }
        
        visit[0]=1;//一定先访问0节点,故预处理
        cout<<0;//一定先访问0节点,故预处理(方便处理输出格式)
        DFS(0);
        cout<<endl;

    }

    return 0;
}


二. SDUT深度优先搜索练习之神奇的矩环

#include <iostream>
#include <string.h>
using namespace std;

int flag=0;
int visit[202][202];//记录结点有没有被访问过
int n,m;//n行m列
char Map[202][202];//数据图

//四方搜索
void DFS(int x,int y,int xl,int yl)
//x1,y1记录上一次走过的位置
{
    visit[x][y]=1;//走过的就不再走了
    if(flag==1) return;

/*
如果不越界并且map == 某方向前进一格后的map
    {
    如果前进一格的map被访问过,并且不是上一个被访问过的结点
    那么就是有环
    否则:
      如果前进一格的map没有被访问过,则DFS该点    
    }
*/
     if(y-1>=0&&Map[x][y-1]==Map[x][y])
    {
        if(visit[x][y-1]==1&&(x!=xl||y-1!=yl))
        {
            flag=1;
        }
        else if(visit[x][y-1]==0)
         {
             DFS(x,y-1,x,y);
         }
    }

    if(y+1<m&&Map[x][y+1]==Map[x][y])
    {
        if(visit[x][y+1]==1&&(x!=xl||y+1!=yl))
        {
            flag=1;
        }
        else if(visit[x][y+1]==0)
        {
            DFS(x,y+1,x,y);
        }
    }

    if(x+1<n&&Map[x+1][y]==Map[x][y])
    {
        if(visit[x+1][y]==1&&(x+1!=xl||y!=yl))
        {
            flag=1;
        }
        else if(visit[x+1][y]==0)
        {
            DFS(x+1,y,x,y);
        }
    }

   
    if(x-1>=0&&Map[x-1][y]==Map[x][y])
    {
        if(visit[x-1][y]==1&&(x-1!=xl||y!=yl))
        {
            flag=1;
        }
        else if(visit[x-1][y]==0)
      {
           DFS(x-1,y,x,y);
      }
    }

}


int main()
{
    while(cin>>n>>m)
    {
        
        
        int i,j;
        for(i=0; i<n; i++)
        {
             cin>>Map[i];
        }
        
        memset(visit,0,sizeof(visit));
        flag=0;
      
        for(i=0;i<n;i++)
        {
            for(j=0;j<m;j++)
            {
                if(visit[i][j]==0)
                {
                    DFS(i,j,i,j);
                }
                if(flag==1)
                {
                    break;      //剪枝
                }
            }
            if(flag==1)
            {
                break;  //剪枝
            }
        }
        if(flag==1)
        {
             cout <<"Yes"<<endl;
        }
        else
        {
           cout <<"No"<<endl;
        }

    }
    return 0;
}


三. 数据结构实验之栈与队列十:走迷宫
二. 类似
这名字起的......,题目和名字没有关系

#include <iostream>
#include <string.h>
using namespace std;

int add=0;//累加器
int visit[112][112];//记录结点有没有被访问过
int n,m;//n行m列
int graph[112][112];//数据图

//四方搜索
void DFS(int x,int y)
{
    if(graph[x][y]==1) return;
    if(visit[x][y]==1) return;
    if(x==n-1&&y==m-1)
    {
        add++;
    }
    else
    {
         if( x < 0  || x >= n
            ||y < 0  || y >= m
            ||graph[x][y] == 1)
        return ;
         if(visit[x][y] == 0)
    {
        visit[x][y] = 1;
        DFS(x + 1, y);
        DFS(x, y + 1);
        DFS(x - 1, y);
        DFS(x, y - 1);
        visit[x][y] = 0;
    }

    }
}


int main()
{
   int t;
   cin>>t;
   while(t--)
   {
       cin>>n>>m;
       int i,j;
       for(i=0;i<n;i++)
       {
           for(j=0;j<m;j++)
           {
             cin>>graph[i][j];
           }
       }
       add=0;
       memset(visit,0,sizeof(visit));
       DFS(0,0);
       cout<<add<<endl;
   }
    return 0;
}



广度优先搜索(BFS)

思想:

先访问完一个节点的所有邻接点,然后按照邻接点的被访问顺序,重复此过程,直到所有节点都被访问。

类似于:树的层次遍历

代码

代码思想:每次取出一个元素,放入与该元素相连的其他结点
image
伪代码:

Code

void BFS(ALGraph G,int v)//非递归
{
    int visited[G.vexnum];//用作该节点有没有被访问过
    memset(visited,0,sizeof(visited));
//
    cout<<v;
    visited[v]=1;
//
    initQueue(Q);//初始化队列Q
    EnQueue(Q,v);//v进队
    while(!QueueEmpty(Q))//队列非空
    {
        DeQueue(Q,u);//队头元素出队并置为u
        for(int w=FirstAdjVex(G,u);w>=0;w=NextAdjVex(G,u,w))
        {
            if(!visited[w])
            {
                cout<< w;
			    visited[w]=1;
                EnQueue(Q,w);//w进队
            }
        }
    }
}

c++代码(非递归实现):

#include<bits/stdc++.h>
using namespace std;
queue<int> Q;//队列
int n,m,k;//n个点,m条边,出发点为k
int graph[50][50];//图
int visited[50];//标记走没走过
void BFS(int v)
{
    Q.push(v);
    visited[v]=1;
    while(!Q.empty())
    {
        int o;
        o=Q.front();
        Q.pop();
        cout<<o<<" ";
        for(int i=0;i<=n;i++)
        {
            if(visited[i]==0&&graph[o][i]==1)
            {
                Q.push(i);
                visited[i]=1;
            }
        }
    }
}
int main()
{
    int t;
    cin>>t;//t组数据
    while(t--)
    {


   memset(graph,0,sizeof(graph));

   memset(visited,0,sizeof(visited));
   cin>>n>>m>>k;//n个点,m条边,出发点为k
   int x,y;
   int i;
   for(i=0;i<m;i++)
   {
       cin>>x>>y;
       graph[x][y]=graph[y][x]=1;
   }

   BFS(k);
   cout<<endl;
       }
    return 0;
}

邻接矩阵时间复杂度:O(n²)
邻接表时间复杂度O(m+e)
空间复杂度O(n)

posted @ 2022-04-01 17:15  kingwzun  阅读(203)  评论(0编辑  收藏  举报