圖的深度優先搜尋/Depth-first search/C++

來源:互聯網
上載者:User

圖是一種常見的資料結構,深度優先和廣度優先搜尋都是常用的演算法,這篇博文先介紹深度優先搜尋。

和往常一樣的,我會用樸實的語言來介紹它,所以只要認真看一定能理解。開始會先介紹的表示方法,如果已經掌握了大可跳過。

圖的表示

要表示一個圖G(V,E)有兩種常見的表示方法,鄰接矩陣和鄰接表。這兩種方法可用於有向圖和無向圖。對於稀疏圖,常用鄰接表表示,

它佔用的空間|E|要小於|V|*|V|。

鄰接表:

圖G(V,E)的鄰接表表示由一個包含V列表的數組Adj組成,其中的每個列表對應於V中的一個頂點,對於v中的任意一個點u,靈界表Adj[u]

包含所有滿足條件(u,v)屬於E的點v,也就是Adj[u]中包含所有和u相鄰的點。

鄰接矩陣:

用一個矩陣表示,矩陣的橫向和縱向分別為圖中的點的有序排列,如果兩個點之間有邊相連對應的矩陣中的元素就是1,反之就是0.

看執行個體就能很好的理解~

對於一個無向圖,所有鄰接表的長度之和是2|E|,如果是有向圖為|E|(無向圖的每一條邊都被表示了兩遍)

它有潛在的不足之處,如果要判斷邊(u,v)是否存在,只能在表Adj[u]中搜尋v。如果有則存在,沒有則不存在。

在圖G(V,E)的鄰接矩陣標記法中,假定個頂點按照某種任意的方式編號1,2,3、、|V|,那麼G的鄰接矩陣就是一個

|V|*|V|的舉證A=(aij),它滿足:

它要佔用|V|*|V|的空間,和邊的數量無關。

深度優先搜尋:

深度優先搜尋是儘可能深的搜尋一個圖,對於一個新發現的節點,如果還有以此為起點還未探測到的邊,就沿此邊探測下去。

當頂點v的所有邊都被探尋過後,搜尋將回溯到發現頂點v的起始點的那些邊。這一過程一直進行到一發現從原點可達的所有點為止。

如果還存在未發現的頂點,則選擇其中一個座位源頂點,重複上過程。

補充:

1、在這個過程中可以記錄每個點訪問的時間。

在訪問點的時候記錄下一個時間 t_start,當這個點所有鄰居都被訪問的時候記錄時間 t_end.那麼訪問的時間 t =t_end-t_start.

在演算法中開始和結束的時間描述為d[u]和f[u].

2、在每一次深度優先遍曆的時候都記錄下訪問節點的前驅節點,可以用一個數組 f[i] 來存放,當完成遍曆的是,就可以利用 f[i] 裡面的資料來得到深度遍曆的順序。它的逆序就是

這個圖的一個拓撲排序。

搜尋過程中,可以通過對頂點著色來表示頂點的狀態,開始時每個頂點都是白色,搜尋過程中被發先置為灰色,

結束時變為黑色,也就是每個有其他鄰居可方位的時候。並且用d[u]和f[u]來記錄點開始方問和結束訪問的時間。

Vertices initially colored white

Then colored gray when discovered

Then black when finished

d[u]: discovery time, a counter indicating when vertex u is discovered.

f[u]: finishing time, a counter indicating when the processing of vertex u (and the processing of all its descendants ) is finished.

演算法描述:

1-3行把所有點置為白的,第三行把每個節點的父節點設定為空白。第四行讓時間計數為0。 5-7行一次檢索v中的頂點,如果是白色,

就調用DFS-VISIT訪問該節點。每次調用DFS-VISIT(u)時,u就成為深度優先遍曆中的一顆樹根。

調用DFS-VISIT(u)是,開始u置為灰色,第二行讓time增值,第三行記錄u的訪問開始時間d[u],4-7行檢查u的鄰居,如果存在沒有被

訪問的點,則深度優先遍曆該點。第8行,因為訪問了u 的所有鄰居,u成了死節點,把u的顏色置為黑色,第9行記錄u的訪問結束時間。

深度優先遍曆的過程可以用表示:

 

深度優先搜尋的結果可能依賴於第DFS中5行中各個節點的訪問順序,也可能依賴於DFS-VISIT中的第4行中u的鄰居的訪問順序。

下面是c++實現:

View Code

/*
圖的深度優先遍曆
出處:一條魚@部落格園 http://www.cnblogs.com/yanlingyin/
2011-12-26

*/
#include <stdlib.h>
#include <stdio.h>

struct node /* 圖頂點結構定義 */
{
int vertex; /* 頂點資料資訊 */
struct node *nextnode; /* 指下一頂點的指標 */
};
typedef struct node *graph; /* 圖形的結構新型態 */
struct node head[9]; /* 圖形頂點數組 */
int visited[9]; /* 遍曆標記數組 */

/********************根據已有的資訊建立鄰接表********************/
void creategraph(int node[20][2],int num)/*num指的是圖的邊數*/
{
graph newnode; /*指向新節點的指標定義*/
graph ptr;
int from; /* 邊的起點 */
int to; /* 邊的終點 */
int i;
for ( i = 0; i < num; i++ ) /* 讀取邊線資訊,插入鄰接表*/
{
from = node[i][0]; /* 邊線的起點 */
to = node[i][1]; /* 邊線的終點 */

/* 建立新頂點 */
newnode = ( graph ) malloc(sizeof(struct node));
newnode->vertex = to; /* 建立頂點內容 */
newnode->nextnode = NULL; /* 設定指標初值 */
ptr = &(head[from]); /* 頂點位置 */
while ( ptr->nextnode != NULL ) /* 遍曆至鏈表尾 */
ptr = ptr->nextnode; /* 下一個頂點 */
ptr->nextnode = newnode; /* 插入節點 */
}
}

/********************** 圖的深度優先搜尋法********************/
void dfs(int current)
{
graph ptr;
visited[current] = 1; /* 記錄已遍曆過 */
printf("vertex[%d]\n",current); /* 輸出遍曆頂點值 */
ptr = head[current].nextnode; /* 頂點位置 */
while ( ptr != NULL ) /* 遍曆至鏈表尾 */
{
if ( visited[ptr->vertex] == 0 ) /* 如過沒遍曆過 */
dfs(ptr->vertex); /* 遞迴遍曆呼叫 */
ptr = ptr->nextnode; /* 下一個頂點 */
}
}

/****************************** 主程式******************************/
int main()
{
graph ptr;
int node[20][2] = { {1, 2}, {2, 1}, /* 邊線數組 */
{1, 3}, {3, 1},
{1, 4}, {4, 1},
{2, 5}, {5, 2},
{2, 6}, {6, 2},
{3, 7}, {7, 3},
{4, 7}, {4, 4},
{5, 8}, {8, 5},
{6, 7}, {7, 6},
{7, 8}, {8, 7} };
int i;
//clrscr();
for ( i = 1; i <= 8; i++ ) /* 頂點數組初始化 */
{
head[i].vertex = i; /* 設定頂點值 */
head[i].nextnode = NULL; /* 指標為空白 */
visited[i] = 0; /* 設定遍曆初始標誌 */
}
creategraph(node,20); /* 建立鄰接表 */
printf("Content of the gragh's ADlist is:\n");
for ( i = 1; i <= 8; i++ )
{
printf("vertex%d ->",head[i].vertex); /* 頂點值 */
ptr = head[i].nextnode; /* 頂點位置 */
while ( ptr != NULL ) /* 遍曆至鏈表尾 */
{
printf(" %d ",ptr->vertex); /* 印出頂點內容 */
ptr = ptr->nextnode; /* 下一個頂點 */
}
printf("\n"); /* 換行 */
}
printf("\nThe end of the dfs are:\n");
dfs(1); /* 列印輸出遍曆過程 */
printf("\n"); /* 換行 */
puts(" Press any key to quit...");
// getch();
}

以上代碼cfree5上編譯通過。

 

 

 

 

圖的深度優先搜尋可以用棧來實現,對某一層的點比如有A,B,C都把他們入棧,每次都把棧頂元素的孩子入棧,當某個點沒有孩子的時候,

就回退到有孩子的節點,把它的孩子入棧,重複上過程,直到根節點的每一個孩子都入棧,最後的出棧順序就是深度優先遍曆的順序。

相應的,廣度優先搜尋利用隊列來實現,對於某一層的點A,B,C,把他們入隊列,然後隊列頭出隊列,對頭的孩子入隊列,如果A有孩子M,N

,那麼A出隊列後隊列為:BCMN,下一步就是B出隊列,B的孩子入隊列、、、、最後出隊列的順序就是廣度優先遍曆的順序。

 下一篇將會介紹廣度優先搜尋演算法~

 

參考資料:《Algorithms》

http://en.wikipedia.org/wiki/Depth-first_search

如有轉載請註明出處:http://www.cnblogs.com/yanlingyin/

一條魚@部落格園

2011-12-26

 

 

 

 

 

 

 

 

 

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.