淺談圖的深度優先遍歷


一、圖的深度優先概述

圖,就是由一些小圓點(稱為頂點)和連接這些小圓點的直線(稱為邊)組成的。例如:

上圖是由五個頂點(編號為1、2、3、4、5)和五條邊(1-2、1-3、1-5、2-4、3-5)組成。

 

現在我們從1號頂點開始遍歷這個圖(遍歷指的是把每一個頂點都訪問一次)。使用深度優先搜索來遍歷這個圖我們將得到以下結果:

 

使用深度優先搜索來遍歷這個圖的具體過程是:

  1. 首先從一個未走到過的頂點作為起始頂點,比如1號頂點作為起點。
  2. 沿1號頂點的邊去嘗試訪問其它未走到過的頂點,首先發現2號頂點還沒有走到過,於是來到了2號頂點。
  3. 再以2號頂點作為出發點繼續嘗試訪問其它未走到過的頂點,這樣又來到了4號頂點。
  4. 再以4號頂點作為出發點繼續嘗試訪問其它未走到過的頂點。
  5. 但是,此時沿4號頂點的邊,已經不能訪問到其它未走到過的頂點了,所以需要返回到2號頂點。
  6. 返回到2號頂點后,發現沿2號頂點的邊也不能再訪問到其它未走到過的頂點。此時又會來到3號頂點(2->1->3),再以3號頂點作為出發點繼續訪問其它未走到過的頂點,於是又來到了5號頂點。
  7. 至此,所有頂點我們都走到過了,遍歷結束。

深度優先遍歷的主要思想是:

  1. 首先以一個未被訪問過的頂點作為起始頂點,沿當前頂點的邊走到未訪問過的頂點;
  2. 當沒有未訪問過的頂點時,則回到上一個頂點,繼續試探別的頂點,直到所有的頂點都被訪問過。

在此我想用一句話來形容 “一路走到頭,不撞牆不回頭”。

 

二、實現

顯而易見,深度優先搜索遍歷是沿着圖的某一條分支遍歷直到末端,然后回溯,再沿着另一條進行同樣的遍歷,直到所有的頂點都被訪問過為止。

那么問題來了,該如何實現這一過程呢?

首先,我們來解決如何存儲一個圖的問題。最常用的方法是使用一個二維數組e來存儲,如下:

 

上圖二維數組中第 i 行第 j 列表示的就是頂點 i 到頂點 j 是否有邊。1 表示有邊,∞ 表示沒有邊,0 表示自己到自己(i=j)。這種存儲圖的方法稱為圖的鄰接矩陣存儲法

同時我們發現:這個二維數組是沿着主對角線對稱的,因此上面這個圖是無向圖。無向圖指的是圖的邊沒有方向,例如邊1-5表示,1號頂點可以到5號頂點,5號頂點也可以到達1號頂點。

void dfs(int cur)//cur是當前所在的頂點編號 
{
    printf("%d ",cur);
    sum++;  //每訪問一個頂點sum就加1 
    if(sum==n) return;  //所有的頂點都已經訪問過則直接退出 
    for(i=1;i<=n;i++)  //從1號頂點到n號頂點依次嘗試,看哪些頂點與當前頂點cur有邊相連 
    {
        //判斷當前頂點cur到頂點i是否有邊,並判斷頂點i是否已訪問過
        if(e[cur][i]==1 && book[i]==0)
        {
            book[i]==1;  //標記頂點i已經訪問過 
            dfs(i);  //從頂點i再出發繼續遍歷 
         } 
    }
    return;
 } 

 

在上面的代碼中變量cur存儲的是當前正在遍歷的頂點,二維數組e存儲的就是圖的邊(鄰接矩陣),數組 book 用來記錄哪些頂點已經訪問過,變量 sum 用來記錄已經訪問過多少個頂點,變量 n 存儲的是圖的頂點的總個數。完整代碼如下:

#include<stdio.h>
int book[101],sum,n,e[101][101];
void dfs(int cur)//cur是當前所在的頂點編號 
{
    int i;
    printf("%d ",cur);
    sum++;  //每訪問一個頂點sum就加1 
    if(sum==n) return;  //所有的頂點都已經訪問過則直接退出 
    for(i=1;i<=n;i++)  //從1號頂點到n號頂點依次嘗試,看哪些頂點與當前頂點cur有邊相連 
    {
        //判斷當前頂點cur到頂點i是否有邊,並判斷頂點i是否已訪問過
        if(e[cur][i]==1 && book[i]==0)
        {
            book[i]==1;  //標記頂點i已經訪問過 
            dfs(i);  //從頂點i再出發繼續遍歷 
         } 
    }
    return;
 } 
 
 int main()
 {
     int i,j,m,a,b;
     scanf("%d %d",&n,&m);
     for(i=1;i<=n;i++)  //初始化二維矩陣
         for(j=1;j<=n;j++)
             if(i == j) e[i][j]=0;
             else e[i][j]=99999999;  //在這里假設99999999為正無窮 
             
    //讀入頂點之間的邊         
    for(i=1;i<=m;i++)
    {
        scanf("%d %d",&a,&b);
        e[a][b] = 1;  
        e[b][a] = 1;//這里是無向圖,所以需要將e[b][a]也賦為1 
     } 
     
    //從1號頂點出發
    book[1]=1;  //標記1號頂點已被訪問 
    dfs(1);  //從1號頂點開始遍歷 
    
    getchar();getchar();
    return 0; 
 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM