1、深度優先搜索(Depth-First-Search 簡稱:DFS)算法
1.1 遍歷過程:數組
(1)從圖中某個頂點v出發,訪問v。數據結構
(2)找出剛纔第一個被頂點訪問的鄰接點。訪問該頂點。以這個頂點爲新的頂點,重複此步驟,直到訪問過的頂點沒有未被訪問過的頂點爲止。spa
(3)返回到步驟(2)中的被頂點v訪問的,且還沒被訪問的鄰接點,找出該點的下一個未被訪問的鄰接點,訪問該頂點。設計
(4)重複(2) (3) 直到每一個點都被訪問過,遍歷結束。3d
例無權圖:(默認爲字母順序)指針
(1)從頂點A出發,訪問該圖code
(2)A的鄰接點爲BEF 以B爲頂點開始訪問 B的鄰接點有FDCblog
(3)B的全部的點均被訪問結束,訪問頂點C 頂點C還有F沒有被訪問遞歸
,結束遍歷。
故遍歷結果爲 A->B->C->D->E->F
有向圖:(默認爲字母順序)
(1)從頂點A出發,訪問該圖
(2)A 的出路頂點爲B、D ,從頂點B 開始訪問, B的出路只有E 結束此路;
(3)開始訪問頂點D,D的出路爲頂點C和F 此時全部頂點都被遍歷了,結束;
故遍歷結果爲: A->B->E->D->C->F
1.2 算法描述
天然語言:從圖中的某個頂點v出發,訪問v,並將visited[v]的值爲true。
一次檢查v的全部鄰接點w,若是visited[w]的值爲flase,再從w出發進行遞歸遍歷,直到圖中的全部頂點都被訪問過。
僞代碼:
遞歸算法:
visited[MVNum] <-- false
count<--v,visited[v]<--true;
for(w<--FirstAdjVex(G,v);w>=0;w<--NextAdjVex(G,v,w))
if(!visited[w] DFS[G,w]);
採用鄰接矩陣表示:
//輸入圖G(V,E),w表示v的鄰接點
//輸出鄰接矩陣
count<--v; visited[v]<--true;
for(w<--0;w<G.vexnum;w++)
if( (G.arcs[v][w]!=0)&&(!visited[w]) )
DFS(G,w);
採用鄰接表:
count<--v; visited[v]<--true;
p<--G.vertices[v].firstarc;
while(p!=NULL) do
w<--p->adjvex;
if(!visited[w]) do DFS(G,w)
p<-- p->nextarc;
1.3用途:檢查圖的連通性和無環性
1.4總結:每一個頂點至多進一次隊列。遍歷圖的過程實質上市經過邊找鄰接點的過程。所以DFS時間複雜度,當用鄰接矩陣表示圖時爲O(n2),其中n爲圖中的頂點數,當以鄰接表作圖的存儲結構時,時間複雜度爲O(e)這裏e爲 圖中的邊數,所以,當以鄰接表爲存儲結構時,DFS時間複雜度爲O(n+e)。
2、廣度優先搜索(Breadth-First-Search 簡稱:BFS)
2.1遍歷過程以下:
(1)從圖中某個頂點v出發,訪問v。
(2)依次訪問v鄰接各個未訪問過的的全部頂點
(3)接着從這些鄰接頂點中繼續訪問它們的鄰接頂點,遵循原則 先被訪問的頂點的鄰接點 先於 後被訪問的頂點的鄰接點 被訪問。重複(3)步驟,直至全部的頂點都被訪問過。
這裏的「先被訪問的頂點的鄰接點 」指的是在第二步驟先訪問的頂點而後再先訪問他的鄰接點,包括後來的第三步驟也是這個意思,均爲上一步驟 先訪問的頂點而後再先訪問他的鄰接點。
例:圖仍是上面的那張無權圖
咱們按照字母ABCDEF這樣的順序來排列
(1)以A爲頂點,開始遍歷
(2)A的三個鄰接點BEF
(3)根據字母順序 從點B開始訪問 B的臨界點有CD 此時,全部的頂點均被訪問
故,遍歷後的結果爲 A ->B-> E-> F-> C-> D
若爲有向圖
(1)根據字母順序,先從頂點A開始訪問
(2)看頂點A的出路,鄰接點爲B,D 。根據字母順序,下一個頂點從B開始
(3)頂點B的出路爲E ,且E沒有出路了,故此路結束
(4)回到和B點同一級的 還有頂點D尚未被訪問 D的出路有兩條,分別爲鄰接點C 和F ,此時全部的頂點都被訪問過。
故 遍歷後的順序爲 A->B->D->E->C->F
2.2算法描述
天然語言:從圖 中的某個頂點v出發,訪問v,並將visited[v]的值爲true,而後將v進隊
只要隊列不空,則重複下述處理:
隊頭頂點u出隊
依次檢查u的全部鄰接點w,若是visited[w]的值爲false,則訪問w,並將visited[w]的數值爲true,而後將w入隊;
僞代碼: //BFS算法描述
//輸入:圖G=<V,E>
//輸出:圖G的BFS遍歷後的前後次序
visited[v] <--true
InitQueue(Q);
EnQueue(Q,v);
while(!QueueEmpty(Q)) do
DeQueue(Q,u);
for(w <--FirstAdjVex(G,u);w>=0;w<--NextAdjVex(G,u,w))
if(!visited[w]) do
count<<w; visited[w] <--true;
EnQueue(Q,w);
2.3用途:計算最短路徑問題
2.4.總結:每一個頂點至多進一次隊列。遍歷圖的過程實質上市經過邊找鄰接點的過程。所以BFS時間複雜度,當用鄰接矩陣表示圖時爲O(n2),其中n爲圖中的頂點數,當以鄰接表作圖的存儲結構時,時間複雜度爲O(e)這裏e爲 圖中的邊數,所以,當以鄰接表爲存儲結構時,BFS時間複雜度爲O(n+e)。
具體的代碼實現以下所示:
#include<stdio.h> #define N 20 #define TRUE 1 #define FALSE 0 int visited[N]; /*訪問標誌數組*/ typedef struct /*隊列的定義*/ { int data[N]; int front,rear; }queue; typedef struct /*圖的鄰接矩陣*/ { int vexnum,arcnum; char vexs[N]; int arcs[N][N]; } graph; void createGraph(graph *g); /*創建一個無向圖的鄰接矩陣*/ void dfs(int i,graph *g); /*從第i個頂點出發深度優先搜索*/ void tdfs(graph *g); /*深度優先搜索整個圖*/ void bfs(int k,graph *g); /*從第k個頂點廣度優先搜索*/ void tbfs(graph *g); /*廣度優先搜索整個圖*/ void init_visit(); /*初始化訪問標識數組*/ /*創建一個無向圖的鄰接矩陣*/ void createGraph(graph *g) { int i,j; char v; g->vexnum=0; g->arcnum=0; i=0; printf("\n輸入頂點序列(以#結束):\n"); while ((v=getchar())!='#') { g->vexs[i]=v; /*讀入頂點信息*/ i++; } g->vexnum=i; /*頂點數目*/ for (i=0;i<g->vexnum;i++) /*鄰接矩陣初始化*/ for (j=0;j<g->vexnum;j++) g->arcs[i][j] = 0;/*(1)-鄰接矩陣元素初始化爲0*/ printf("\n輸入邊的信息(頂點序號,頂點序號),以(-1,-1)結束:\n"); scanf("%d,%d",&i,&j); /*讀入邊(i,j)*/ while (i!=-1) /*讀入i爲-1時結束*/ { g->arcs[i][j] = 1; /*(2)-i,j對應邊等於1*/ g->arcnum++; scanf("%d,%d",&i,&j); } }/* createGraph */ /*(3)---從第i個頂點出發深度優先搜索,補充完整算法*/ void dfs(int i,graph *g) { int j; printf("%c", g->vexs[i]); visited[i] = TRUE; for (j = 0; j < g->vexnum; j++) if (g->arcs[i][j] == 1 && !visited[j]) dfs(j, g); }/* dfs */ /*深度優先搜索整個圖*/ void tdfs(graph *g) { int i; printf("\n從頂點%C開始深度優先搜索序列:",g->vexs[0]); for (i=0;i<g->vexnum;i++) if (visited[i] != TRUE) /*(4)---對還沒有訪問過的頂點進行深度優先搜索*/ dfs(i,g); printf("\n"); }/*tdfs*/ /*從第k個頂點廣度優先搜索*/ void bfs(int k,graph *g) { int i,j; queue qlist,*q; q=&qlist; q->rear=0; q->front=0; printf("%c",g->vexs[k]); visited[k]=TRUE; q->data[q->rear]=k; q->rear=(q->rear+1)%N; while (q->rear!=q->front) /*當隊列不爲空,進行搜索*/ { i=q->data[q->front]; q->front=(q->front+1)%N; for (j=0;j<g->vexnum;j++) if ((g->arcs[i][j]==1)&&(!visited[j])) { printf("%c",g->vexs[j]); visited[j]=TRUE; q->data[q->rear] = j; /*(5)---剛訪問過的結點入隊*/ q->rear = (q->rear + 1) % N; /*(6)---修改隊尾指針*/ } } }/*bfs*/ /*廣度優先搜索整個圖*/ void tbfs(graph *g) { int i; printf("\n從頂點%C開始廣度優先搜索序列:",g->vexs[0]); for (i=0;i<g->vexnum;i++) if (visited[i]!=TRUE) bfs(i,g); /*從頂點i開始廣度優先搜索*/ printf("\n"); }/*tbfs*/ void init_visit() /*初始化訪問標識數組*/ { int i; for (i=0;i<N;i++) visited[i]=FALSE; } int main() { graph ga; int i,j; printf("***********圖鄰接矩陣存儲和圖的遍歷***********\n"); printf("\n1-輸入圖的基本信息:\n"); createGraph(&ga); printf("\n2-無向圖的鄰接矩陣:\n"); for (i=0;i<ga.vexnum;i++) { for (j=0;j<ga.vexnum;j++) printf("%3d",ga.arcs[i][j]); printf("\n"); } printf("\n3-圖的遍歷:\n"); init_visit(); /*初始化訪問數組*/ tdfs(&ga); /*深度優先搜索圖*/ init_visit(); tbfs(&ga); /*廣度優先搜索圖*/ return 0; }
運行結果(輸入的爲本節中一直用到的無向圖)
深度和廣度查找不一樣之處在於對頂點的訪問順序不一樣。
第一次寫博客,應該仍是有點問題的(雖然也查了一些資料~.~)
參考資料:
《數據結構(C語言版)》 嚴蔚敏 李冬梅 吳偉民著 人民郵電出版社
《程序設計中實用的數據結構 》 王建德 吳永輝著 人民郵電出版社