1. 程式人生 > >數據結構與算法10—圖的遍歷

數據結構與算法10—圖的遍歷

描述 回路 ted oid 實現 color 廣度優先搜索 printf 剛才

圖的遍歷

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出發的深度優先搜索遍歷序列可有多種,下面僅給出三種,其它可作類似分析。

技術分享圖片

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. 用鄰接矩陣實現圖的深度優先搜索

技術分享圖片

#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。同樣可以分析出從其它頂點出發的遍歷結果。

技術分享圖片

2. 用鄰接表實現圖的深度優先搜索

技術分享圖片

圖的鄰接表存儲結構定義:

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

技術分享圖片

廣度優先搜索

廣度優先搜索的思想

  • 首先訪問頂點i,並將其訪問標誌置為已被訪問,即visited[i]=1;
  • 接著依次訪問與頂點i有邊相連的所有頂點W1,W2,…,Wt;
  • 然後再按順序訪問與W1,W2,…,Wt有邊相連又未曾訪問過的頂點;
  • 依此類推,直到圖中所有頂點都被訪問完為止 。

在無向圖G7中,從頂點1出發的廣度優先搜索遍歷序列舉三種為:

技術分享圖片

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. 用鄰接矩陣實現圖的廣度優先搜索遍歷

技術分享圖片

根據該算法用及圖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. 用鄰接表實現圖的廣序優先搜索遍歷

技術分享圖片

可以得到圖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;            /*找下一個鄰接點*/
        } 
    }
}

數據結構與算法10—圖的遍歷