資料結構——樹的深搜演算法
樹的深度搜索(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;
在第五行中, 2 和 8 已被訪問,返回第八行;
在第八行中,沒有未被訪問的點,返回第四行;
在第四行中,沒有未被訪問的點,返回第二行;
在第二行中,沒有未被訪問的點,返回第一行;
在第一行中, 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的點中已沒有未被訪問的點,深搜結束。
(全文僅代表個人理解)