1. 程式人生 > 實用技巧 >資料結構——樹的深搜演算法

資料結構——樹的深搜演算法

樹的深度搜索(DFS)演算法

一些概念

圖的遍歷

從圖中某一頂點出發訪遍圖中其餘頂點,且使每一個頂點有且僅被訪問一次

圖的遍歷的意義

是求解圖的連通性問題、拓撲排序和求關鍵路徑等演算法的基礎。

圖的遍歷通常有兩種方法,即深度優先搜尋和廣度優先搜尋

下面介紹深度優先搜尋(DFS Depth_First Search)

事先準備:

因為圖的遍歷要求每個頂點有且只被訪問一次,所以就需要一個輔助陣列visited[](可用bool型別或其他型別)來代表該頂點是否被訪問過。

演算法流程:

鄰接矩陣儲存方式

①將所有點設定為未被訪問狀態;

②用下標v,按頂點向量陣列的順序訪問每個未被訪問的點;

③對於鄰接矩陣,將下標為v的元素設定為已訪問,並輸出該點資訊(這裡用輸出代表訪問),遍歷下標第v行的鄰接矩陣元素,遇到非零並且未被訪問過的下標w時,跳轉到第w行;

④重複執行第③步。

鄰接表儲存方式

①將所有點設定為未被訪問狀態;

②用下標v,按頂點向量表的順序訪問每個未被訪問的點;

③對於鄰接表的表結點,將下標為v的元素設定為已訪問,並輸出該點資訊(這裡用輸出代表訪問),遍歷下標第v個元素所在的鄰接表的表結點,遇到未被訪問過的結點時,跳轉到該結點所在行w;

④重複執行第③步。

鄰接矩陣儲存方式C語言實現

void DFS(MGraph G, int v, bool visited[])//深度搜索 
{
    visited[v] = true;//將點v設定為已訪問 
    cout<<G.vexs[v];
    for(int w = 0
; w < G.vexnum; w++) { if((G.arcs[v][w] == 1) && !visited[w]) DFS(G, w, visited); } } void DFSTravrese(MGraph G, bool visited[]) { for(int i = 0 ; i < G.vexnum; i++)//初始化訪問陣列資訊 visited[i] = false; for(int v = 0; v < G.vexnum; v++) {
if(!visited[v]) DFS(G, v, visited); } }

鄰接表儲存方式C語言實現

void DFS(ALGraph G, bool visited[], int v)
{
    visited[v] = true;
    cout<<setw(5)<<G.vertices[v].data;
    ArcNode *p;
    for(p = G.vertices[v].firstarc; p; p = p->nextarc)
    {
        if(!visited[p->adjvex])
            DFS(G, visited, p->adjvex);    
    }    
}

void DFSTraverse(ALGraph G, bool visited[])
{
    for(int i = 0 ; i < G.vexnum; i++)
        visited[i] = false;
    for(int i = 0; i < G.vexnum; i++)
    {
        if(!visited[i])
        {
            cout<<endl;
            DFS(G, visited, i);    
        }
    } 
}

例子分析

連通圖

鄰接矩陣表達法執行結果如下:

圖的頂點數和邊數: 8 9
圖的頂點資訊:
1 2 3 4 5 6 7 8
圖的鄰接矩陣:

0 1 1 0 0 0 0 0
1 0 0 1 1 0 0 0
1 0 0 0 0 1 1 0
0 1 0 0 0 0 0 1
0 1 0 0 0 0 0 1
0 0 1 0 0 0 1 0
0 0 1 0 0 1 0 0
0 0 0 1 1 0 0 0

該圖的出度資訊:
2 3 3 2 2 2 2 2
該圖的入度資訊:
2 3 3 2 2 2 2 2
深度搜索結果如下:
1 2 4 8 5 3 6 7

分析如下:

在DFSTravrese函式中v=0,即1未被訪問,進入DFS函式,visited[0]變為true,列印 1

在鄰接矩陣中,與 1 鄰接點為 2,進入第二行,進入DFS函式,visited[1]變為true,列印 2

在第二行中, 1 已被訪問過,下一次迴圈, 4 未被訪問,進入第四行,進入DFS函式,visited[3]變為true,列印 4

在第四行中,2已被訪問,下一次迴圈, 8 未被訪問,進入第八行,進入DFS函式,visited[7]變為true,列印8

在第八行中, 4 已被訪問,下一次迴圈, 5未被訪問,進入第五行,進入DFS函式,visited[4]變為true,列印5

在第五行中, 28 已被訪問,返回第八行;

在第八行中,沒有未被訪問的點,返回第四行;

在第四行中,沒有未被訪問的點,返回第二行;

在第二行中,沒有未被訪問的點,返回第一行;

在第一行中, 3 未被訪問,進入第三行,進入DFS函式,visited[2]變為true,列印3

在第三行中, 6 未被訪問,進入第六行,進入DFS函式,visited[5]變為true,列印6

在第六行中, 7 未被訪問,進入第七行,進入DFS函式,visited[6]變為true,列印7

在第七行中,沒有未被訪問的點,返回第六行;

在第六行中,沒有未被訪問的點,返回第三行;

在第三行中,沒有未被訪問的點,返回第一行;

在第一行中,沒有未被訪問的點,返回DFSTravrese函式;

v>0的點中已沒有未被訪問的點,深搜結束。

非連通圖

鄰接表表達法執行結果如下:

圖的頂點數和邊數: 13 13
圖的頂點資訊:
A B C D E F G H I J K L M
圖的鄰接表:
A的鄰接點:L F C B
B的鄰接點:M A
C的鄰接點:A
D的鄰接點:E
E的鄰接點:D
F的鄰接點:A
G的鄰接點:K H I
H的鄰接點:K G
I的鄰接點:G
J的鄰接點:M L
K的鄰接點:H G
L的鄰接點:J M A
M的鄰接點:J L B

該圖的出入度情況如下:

入度資訊:
4 2 1 1 1 1 3 2 1 2 2 3 3
出度資訊:
4 2 1 1 1 1 3 2 1 2 2 3 3
深度搜索結果如下:

A L J M B F C
D E
G K H I

分析如下:

在DFSTravrese函式中v=0,即A未被訪問,進入DFS函式,visited[0]變為true,列印 A;

在鄰接表中,在A的表結點中,與A鄰接的未被訪問的第一個點是L,進入DFS函式,visited[11]變為true,列印 L;

在鄰接表中,在L的表結點中,與L鄰接的未被訪問的第一個點是J,進入DFS函式,visited[9]變為true,列印 J;

在鄰接表中,在J的表結點中,與J鄰接的未被訪問的第一個點是M,進入DFS函式,visited[12]變為true,列印 M;

在鄰接表中,在M的表結點中,與M鄰接的未被訪問的第一個點是B,進入DFS函式,visited[1]變為true,列印 B;

在鄰接表中,在B的表結點中,都被訪問了,返回M結點;

在鄰接表中,在M的表結點中,都被訪問了,返回J結點;

在鄰接表中,在J的表結點中,都被訪問了,返回L結點;

在鄰接表中,在L的表結點中,都被訪問了,返回A結點;

在鄰接表中,在A的表結點中,與A鄰接的未被訪問的第一個點是F,進入DFS函式,visited[6]變為true,列印 F;

在鄰接表中,在F的表結點中,都被訪問了,返回A結點;

在鄰接表中,在A的表結點中,與A鄰接的未被訪問的第一個點是C,進入DFS函式,visited[2]變為true,列印 C;

在鄰接表中,在C的表結點中,都被訪問了,返回A結點;

從A開始沒有未被訪問的點,返回DFSTravrese函式的for迴圈,從D開始訪問;

在鄰接表中,在D的表結點中,與D鄰接的未被訪問的第一個點是E,進入DFS函式,visited[5]變為true,列印 E;

在鄰接表中,在E的表結點中,都被訪問了,返回D結點;

從D開始沒有未被訪問的點,返回DFSTravrese函式的for迴圈,從G開始訪問;

在鄰接表中,在G的表結點中,與G鄰接的未被訪問的第一個點是K,進入DFS函式,visited[10]變為true,列印 K;

在鄰接表中,在K的表結點中,與K鄰接的未被訪問的第一個點是H,進入DFS函式,visited[7]變為true,列印 H;

在鄰接表中,在H的表結點中,都被訪問了,返回K結點;

在鄰接表中,在K的表結點中,都被訪問了,返回G結點;

在鄰接表中,在G的表結點中,與G鄰接的未被訪問的第一個點是I,進入DFS函式,visited[8]變為true,列印 I;

在鄰接表中,在I的表結點中,都被訪問了,返回G結點;

從G開始沒有未被訪問的點,返回DFSTravrese函式的for迴圈;

v>0的點中已沒有未被訪問的點,深搜結束。

(全文僅代表個人理解)