(原創)不過如此的 DFS 深度優先遍歷


DFS 深度優先遍歷 

DFS算法用於遍歷圖結構,旨在遍歷每一個結點,顧名思義,這種方法把遍歷的重點放在深度上,什么意思呢?就是在訪問過的結點做標記的前提下,一條路走到天黑,我們都知道當每一個結點都有很多分支,那么我們的小人就沿着每一個結點走,定一個標准,比如優先走右手邊的路,然后在到達下一個結點前先敲敲門,當一個結點的所有門都被敲了個遍都標記過,那么就走回頭路,再重復敲門,直到返回起點,這樣的方式我們叫做 DFS 深度優先遍歷,本文以圖結構講解,例子取自《大話數據結構》。

如我剛才所講,從A點出發,將路徑畫出來就是以下效果。

實線是走過的路程,虛線就是我們的小人敲門然后發現標記過的一個過程,大家可以寄幾模擬一哈。一句話總結就是:

從圖中某個頂點 v 出發,訪問此頂點,然后從 v 的未被訪問的鄰接點出發 深度優先遍歷圖結構,直至圖中所有和 v 有路徑相通的頂點都被訪問到。

結構定義代碼:

typedef char VertexType;
typedef int EdgeType;

#define MAXVEX 10
#define INFINITY 65535

typedef int boolean;
boolean visited[MAXVEX];

typedef struct
{
    VertexType vexs[MAXVEX];
    EdgeType arc[MAXVEX][MAXVEX];
    int numVertexes,numEdges;
}MGraph;

鄰接矩陣創建:

void CreateMGraph(MGraph *G)
{
    int i,j,k;
    printf("請輸入頂點數和邊數(空格隔開)\n");
    scanf("%d %d",&G->numVertexes,&G->numEdges);
    printf("請依次輸入每個頂點的內容:\n");
    for(i = 0;i < G->numVertexes;i++)
    {
        scanf("%c",&G->vexs[i]);
    }
    for(i = 0;i < G->numVertexes;i++)
    {
        for(j = 0;j < G->numVertexes;j++)
        {
            G->arc[i][j] = INFINITY;
        }
    }
    for(k = 0;k < G->numEdges;k++)
    {
        printf("輸入邊(vi,vj)上的下標i,下標j:\n");
        scanf("%d %d",&i,&j);
        G->arc[i][j] = 1;
        G->arc[j][i] = G->arc[i][j];
    }
}

DFS算法

void DFS(MGraph G,int i) //深度優先遞歸算法
{
    int j;
    visited[i] = 1;
    printf("%c",G.vexs[i]);
    for(j = 0;j < G.numVertexes;j++)
    {
        if(G.arc[i][j] == 1 && !visited[j])
            DFS(G,j);
    }
}
void DFStraverse(MGraph G)  //深度遍歷
{
    int i;
    for(i = 0;i < G.numVertexes;i++)
    visited[i] = 0;
    for(i = 0;i < G.numVertexes;i++)
    {
        if(!visited[i])
            DFS(G,i);
    }
}

這種方法比較好理解在於使用循環進入函數再遞歸,可以保證以鄰接矩陣為儲存單位的每一個格子都被遍歷到,且做好標注,那么用鄰接矩陣的DFS算法時間復雜度可以想見是 O(n²),嵌套兩重循環,

我們來看下一種實現方式,這次我們使用的是鄰接單鏈表

結構定義:

typedef int boolean;
boolean visited[MAXVEX];

typedef char VertexType;
typedef int EdgeType;

#define MAXVEX 10
#define INFINITY 65535

typedef struct EdgeNode //邊表結構點
{
    int adjvex;
    struct EdgeNode *next;
}EdgeNode;

typedef struct VertexNode //頂點表結構點
{
    VertexType data;
    EdgeNode *firstedge;
}VertexNode,AdjList[MAXVEX];

typedef struct //總表結構
{
    AdjList adjList;
    int numVertexes,numEdges;
}GraphAdjList;

比鄰接矩陣復雜一點,但是其結構只有三種,總表、定點表和邊表

創建:

void CreateALGraph(GraphAdjList *G)
{
    int i,j,k;
    EdgeNode *e;
    printf("請輸入頂點數和邊數(空格隔開)\n");
    scanf("%d %d",&G->numVertexes,&G->numEdges);
    for(i = 0;i < G->numVertexes;i++)
    {
        scanf("%c",&G->adjList[i].data);
        G->adjList[i].firstedge = NULL;
    }
    for(k = 0;k < G->numVertexes;k++)
    {
        printf("輸入邊(vi,vj)上的下標i,下標j:\n");
        scanf("%d %d",&i,&j);
        e = (EdgeNode*)malloc(sizeof(EdgeNode));
        e->adjvex=i;
        e->next = adjList[j].firstedge;
        adjList[j].firstedge = e;
        
        e = (EdgeNode*)malloc(sizeof(EdgeNode));
        e->adjvex=j;
        e->next = adjList[i].firstedge;
        adjList[i].firstedge = e;
    }
}

DFS算法實現:

void DFS(GraphAdjList GL,int i)
{
    EdgeNode *p;
    visited[i] = 1;
    printf("%c",GL->adjList[i].data);
    while(p)
    {
        if(!visited[p->adjvex])
            DFS(GL,p->adjvex);
        p = p->next;
    }
}

void DFStraverse(GraphAdjList GL)
{
    int i;
    for(i = 0;i < GL->numVertexes;i++)
    visited[i] = 0;
    for(i = 0;i < GL->numVertexes;i++)
    {
        if(!visited[i])
            DFS(GL,i);
    }
}

利用鄰接表的方式能夠實現相同效果的遍歷,同時這種方法的算法時間復雜度為 O(n+e)

顯然對於點多邊少的稀疏圖來說,鄰接表結構使得算法在時間效率上大大提高。


免責聲明!

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



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