2023-03-02
原文作者:返回主页亦小海 原文地址:https://www.cnblogs.com/lisen10

图的遍历

  1. 在图中有回路,从图中某一顶点出发访问图中其它顶点时,可能又会回到出发点,而图中可能还剩余有顶点没有访问到。

  2. 我们可以设置一个全局型标志数组visited来标志某个顶点是否被访问过,未访问的值为0,访问过的值为1。

  3. 图的遍历有两种方法: 深度优先搜索遍历(DFS )、 广度优先搜索遍历(BFS)

深度优先搜索

深度优先搜索思想

  • 首先访问顶点i,并将其访问标记置为访问过,即visited[i] =1;
  • 然后搜索与顶点 i 有边相连的下一个顶点 j ,若j未被访问过,则访问它,并将j的访问标记置为访问过,visited[j]=1,然后从j开始重复此过程,若j已访问,再看与i有边相连的其它顶点;
  • 若与i有边相连的顶点都被访问过,则退回到前一个访问顶点并重复刚才过程,直到图中所有顶点都被访问完为止。

例如:

对下图所示无向图G7,从顶点1出发的深度优先搜索遍历序列可有多种,下面仅给出三种,其它可作类似分析。

202303022155129021.png

1, 2, 4, 8, 5, 6, 3, 7

1, 2, 5, 8, 4, 7, 3, 6

1, 3, 6, 8, 7, 4, 2, 5

可以看出,从某一个顶点出发的遍历结果是不唯一的。但是,若我们给定图的存贮结构,则从某一顶点出发的遍历结果应是唯一的。

1. 用邻接矩阵实现图的深度优先搜索

202303022155135062.png

    #define MAX_VERTEX_NUM 100
    typedef int VertexType; /*假设图中结点的数据类型为整型*/
    typedef struct  {
       VertexType v[MAX_VERTEX_NUM];     /*顶点表*/
       int A[MAX_VERTEX_NUM][MAX_VERTEX_NUM];   /*邻接矩阵*/
       int vexnum,arcnum; /*图的顶点数和弧数*/
    }MGraph;
    int visited[MAX_VERTEX_NUM];
    void DFSM(MGraph G, int i)
    {  
       printf("%5d",G.v[i]); /*访问顶点i*/
       visited[i]=1;                 /*标记顶点i已访问*/
       for(int j=0;j<G.vexnum;j++) {
          if (!visited[j] && G.A[i][j]==1) 
             DFSM(G,j); /*若某个邻接顶点尚未访问,则递归访问它*/
       }
    }

用上述算法和无向图G7,可以描述从顶点1出发的深度优先搜索遍历过程,其中实线表示下一层递归调用,虚线表示递归调用的返回。 可以得到从顶点1的遍历结果为 1, 2, 4, 8, 5, 6, 3, 7。同样可以分析出从其它顶点出发的遍历结果。

202303022155139833.png

2. 用邻接表实现图的深度优先搜索

202303022155144504.png

图的邻接表存储结构定义:

    typedef struct ArcNode {  
      int    adjvex;  /*该弧所指向的顶点的位置*/
      struct ArcNode  *nextarc; /*下一条弧*/
      InfoType   info;   /*该弧上的权值*/
    } ArcNode;
    typedef int VertexType; 
    typedef struct VNode { 
        VertexType  data;   
        ArcNode  *firstarc; 
    }VNode;
    typedef struct {  
         VNode  vertices[MAXV];
         int   vexnum, arcnum; 
    } ALGraph;

邻接表存储时的深度优先搜索算法:

    int visited[MAX_VERTEX_NUM];
    void DFS(ALGraph G, int v)
    { 
       ArcNode *p;
       printf("%5d",G.vertices[v].data); /*访问顶点v*/
       visited[v]=1;              /*标记顶点v已访问*/
       p=G.vertices[v].firstarc;  /*取第一个邻接边*/
       while (p) {
       if (!visited[p->adjvex]) 
          DFS(G,p->adjvex); /*递归访问*/
          p=p->nextarc;  /*找顶点v的下一个邻接点*/
       }
    }

用刚才算法,可以描述从顶点7出发的深度优先搜索遍历示意图,其中实线表示下一层递归,虚线表示递归返回,箭头旁边数字表示调用的步骤。遍历序列为 7, 3, 1, 2, 4, 8, 5, 6。

202303022155149985.png

广度优先搜索

广度优先搜索的思想

借助队列先进先出的特点实现

  • 首先访问顶点i,并将其访问标志置为已被访问,即visited[i]=1;
  • 接着依次访问与顶点i有边相连的所有顶点W1,W2,…,Wt;
  • 然后再按顺序访问与W1,W2,…,Wt有边相连又未曾访问过的顶点;
  • 依此类推,直到图中所有顶点都被访问完为止 。

在无向图G7中,从顶点1出发的广度优先搜索遍历序列举三种为:

202303022155154966.png

1, 2, 3, 4, 5, 6, 7, 8

1, 3, 2, 7, 6, 5, 4, 8

1, 2, 3, 5, 4, 7, 6, 8

1. 用邻接矩阵实现图的广度优先搜索遍历

202303022155160257.png

根据该算法用及图7-14中的邻接矩阵,可以得到图G7的广度优先搜索序列,

若从顶点1 出发,广度优先搜索序列为:1,2,3, 4,5, 6,7,8。

若从顶点3出发,广度优先搜索序列为:3, 1, 6, 7, 2, 8, 4, 5。

邻接矩阵存储时的宽度优先搜索算法:

    void BFSM(MGraph G,int i)  
    {
        int j;
        Queue Q;  InitQueue(&Q); 
        InQueue(&Q,i);
        printf("%5d",G.v[i]);  /*访问初始顶点v*/
        visited[i]=1;                  /*置已访问标记*/
        while(OutQueue(&Q,&i)) 
        {    /*若队列不空时循环*/
            for(j=0;j<G.vexnum;j++) 
            {
                if (!visited[j] && G.A[i][j]==1) 
                {
                    visited[j]=1;
                    printf("%5d",G.v[j]); /*访问v*/
                    InQueue(&Q,j);     /*该顶点进队*/
                }
            }
        }
    }

2. 用邻接表实现图的广序优先搜索遍历

202303022155165268.png

可以得到图G7的广度优先搜索序列,

若从顶点1出发,广度优先搜索序列为:1,2,3,4,5,6,7,8,

若从顶点7出发,广度优先搜索序列为:7,3,8,1,6,4,5,2。

邻接表存储时的宽度优先搜索算法:

    void BFS(ALGraph G,int v)  
    { 
        ArcNode *p; int x;
        Queue Q;  InitQueue(&Q); InQueue(&Q,v);
        printf("%5d",G.vertices[v].data);  /*访问初始顶点v*/
        visited[v]=1;        /*置已访问标记*/
        while(OutQueue(&Q,&x)) 
        {       /*若队列不空时循环*/
            
            p=G.vertices[x].firstarc;   /*与x邻接的第一个顶点*/
            while(p!=NULL) 
            {
                if (visited[p->adjvex]==0) 
                {   /*若未被访问*/ 
                    visited[p->adjvex]=1;
                    printf("%5d",G.vertices[p->adjvex].data); 
                    InQueue(&Q,p->adjvex);     /*该顶点进队*/
                }
                p=p->nextarc;            /*找下一个邻接点*/
            } 
        }
    }
阅读全文