1. 程式人生 > >資料結構篇:圖的遍歷(一:深度優先遍歷)

資料結構篇:圖的遍歷(一:深度優先遍歷)

深度優先遍歷,也稱作深度優先搜尋,縮寫為DFS

深度優先遍歷從某個頂點出發,訪問此頂點,然後從v的未被訪問的鄰接點觸發深度優先便利圖,直至所有和v有路徑想通的頂點都被訪問到。

這樣我們一定就訪問到所有結點了嗎,沒有,可能還有的分支我們沒有訪問到,所以需要回溯(一般情況下都設定一個數組,來記錄頂點是否訪問到,如果訪問到就不執行DFS演算法,如果未被訪問過就執行DFS演算法)

以這張圖為例

我們約定,在沒有碰到重複頂點的情況下,優先選擇右手邊

那麼按深度優先遍歷就是:A B C D E F G H(此時這條線路已經走到盡頭,可是還有一個I頂點沒有遍歷,所以回到G,發現G的鄰接點都遍歷過了,再回到F,發現F的鄰接點也都遍歷過了。。。直到D頂點,發現I這個頂點沒有遍歷,所以把I再遍歷,繼續回溯,最終回到起點A) I

落實到程式碼就是


//訪問標誌的陣列,為1表示訪問過,為0表示未被訪問
int visted[100];
//鄰接表的深度優先遍歷演算法
void AdjacencyList::DFS(GraphAdjList *G, int i) {
    EdgeNode *p;
    visted[i] = 1;
    cout << G->adjList[i].data << "--";
    p = G->adjList[i].firstedge;
    while (p)
    {
        if (!visted[p->adjvex])
        {
            //遞迴訪問
            DFS(G, p->adjvex);
        }
        p = p->next;
    }

}
//鄰接表的深度遍歷操作
void AdjacencyList::DFSTraverse(GraphAdjList *G) {
    //初始化所有頂點都沒有訪問過
    cout<<"深度優先遍歷結果為:"<<endl;
    for (int i = 0; i < G->numVertexes; i++)
    {
        visted[i] = 0;
    }
    for (int i = 0; i < G->numVertexes; i++)
    {
        if (visted[i] == 0)
        {
            DFS(G, i);
        }
    }
}

完整程式碼

//
// Created by 煙雨迷離半世殤 on 2018/11/21.
//

#include <iostream>

using namespace std;

//訪問標誌的陣列,為1表示訪問過,為0表示未被訪問
int visted[100];
//邊表結點
typedef struct EdgeNode {
    //頂點對應的下標
    int adjvex;
    //指向下一個鄰接點
    struct EdgeNode *next;
} edgeNode;

//頂點表結點
typedef struct VertexNode {
    //頂點資料
    char data;
    //邊表頭指標
    edgeNode *firstedge;
} VertexNode, AdjList[100];

//集合
typedef struct {
    AdjList adjList;
    //頂點數和邊數
    int numVertexes, numEdges;
} GraphAdjList;

class AdjacencyList {
public:

    void CreateALGraph(GraphAdjList *G);

    void ShowALGraph(GraphAdjList *G);

    void DFS(GraphAdjList *G, int i);

    void DFSTraverse(GraphAdjList *G);

    void Test();


};

void AdjacencyList::CreateALGraph(GraphAdjList *G) {
    int i, j, k;
    edgeNode *e;
    cout << "輸入頂點數和邊數" << endl;
    //輸入頂點數和邊數
    cin >> G->numVertexes >> G->numEdges;
    //讀入頂點資訊,建立頂點表
    for (i = 0; i < G->numVertexes; i++)
    {
        //輸入頂點資訊
        cin >> G->adjList[i].data;
        //將邊表置為空表
        G->adjList[i].firstedge = NULL;
    }
    //建立邊表(頭插法)
    for (k = 0; k < G->numEdges; k++)
    {
        cout << "輸入邊(vi,vj)上的頂點序號" << endl;
        cin >> i >> j;
        e = new EdgeNode;
        e->adjvex = j;
        e->next = G->adjList[i].firstedge;
        G->adjList[i].firstedge = e;

        e = new EdgeNode;

        e->adjvex = i;
        e->next = G->adjList[j].firstedge;
        G->adjList[j].firstedge = e;
    }
}

void AdjacencyList::Test() {
    cout << "ALL IS OK." << endl;
}

void AdjacencyList::ShowALGraph(GraphAdjList *G) {
    for (int i = 0; i < G->numVertexes; i++)
    {
        cout << "頂點" << i << ": " << G->adjList[i].data << "--firstedge--";
        edgeNode *p = new edgeNode;
        p = G->adjList[i].firstedge;
        while (p)
        {
            cout << p->adjvex << "--Next--";
            p = p->next;
        }
        cout << "--NULL" << endl;
    }

}

void AdjacencyList::DFS(GraphAdjList *G, int i) {
    EdgeNode *p;
    visted[i] = 1;
    cout << G->adjList[i].data << "--";
    p = G->adjList[i].firstedge;
    while (p)
    {
        if (!visted[p->adjvex])
        {
            //遞迴訪問
            DFS(G, p->adjvex);
        }
        p = p->next;
    }

}

void AdjacencyList::DFSTraverse(GraphAdjList *G) {
    //初始化所有頂點都沒有訪問過
    cout<<"深度優先遍歷結果為:"<<endl;
    for (int i = 0; i < G->numVertexes; i++)
    {
        visted[i] = 0;
    }
    for (int i = 0; i < G->numVertexes; i++)
    {
        if (visted[i] == 0)
        {
            DFS(G, i);
        }
    }
}


int main() {

    AdjacencyList adjacencyList;
    GraphAdjList *GA = new GraphAdjList;
    adjacencyList.Test();
    adjacencyList.CreateALGraph(GA);
    adjacencyList.ShowALGraph(GA);
    adjacencyList.DFSTraverse(GA);
    return 0;
}


以這張圖為基準輸入

執行結果