1. 程式人生 > >演算法導論--圖的遍歷(DFS與BFS)

演算法導論--圖的遍歷(DFS與BFS)

圖的遍歷就是從圖中的某個頂點出發,按某種方法對圖中的所有頂點訪問且僅訪問一次。為了保證圖中的頂點在遍歷過程中僅訪問一次,要為每一個頂點設定一個訪問標誌。通常有兩種方法:深度優先搜尋(DFS)和廣度優先搜尋(BFS).這兩種演算法對有向圖與無向圖均適用。
以下面無向圖為例:
這裡寫圖片描述

1.深度優先搜尋(DFS)

基本步驟:

1.從圖中某個頂點v0出發,首先訪問v0;
2.訪問結點v0的第一個鄰接點,以這個鄰接點vt作為一個新節點,訪問vt所有鄰接點。直到以vt出發的所有節點都被訪問到,回溯到v0的下一個未被訪問過的鄰接點,以這個鄰結點為新節點,重複上述步驟。直到圖中所有與v0相通的所有節點都被訪問到。
3.若此時圖中仍有未被訪問的結點,則另選圖中的一個未被訪問的頂點作為起始點。重複深度優先搜尋過程,直到圖中的所有節點均被訪問過。

這裡寫圖片描述

DFS:A,B,C,F,E,G,D,H,I

2.廣度優先搜尋(BFS)

2.1 BFS類似與樹的層次遍歷,從源頂點s出發,依照層次結構,逐層訪問其他結點。即訪問到距離頂點s為k的所有節點之後,才會繼續訪問距離為k+1的其他結點。
基本步驟:

1.從圖中某個頂點v0出發,首先訪問v0;
2.依次訪問v0的各個未被訪問的鄰接點。
3.依次從上述鄰接點出發,訪問他們的各個未被訪問的鄰接點。始終保證一點:如果vivk之前被訪問,則vi的鄰接點應在vk的鄰接點之前被訪問。重複上述步驟,直到所有頂點都被訪問到。
4.如果還有頂點未被訪問到,則隨機選擇一個作為起始點,重複上述過程,直到圖中所有頂點都被訪問到。

這裡寫圖片描述

BFSA,B,D,E,C,G,F,H,I
為了按照優先訪問頂點的次序,訪問其鄰接點,所以需要建立一個優先佇列(先進先出)。
2.2 採用此演算法還可以很方便計算距離任一頂點vi的路徑長度為k的所有頂點;從頂點vi出發進行廣度優先搜尋,可以記錄到每一步,兩步,…,k步可到達的頂點。採用一個距離佇列與訪問佇列同步,距離佇列是訪問佇列中對應頂點距離vi的距離。例如距離頂點B為2的頂點為D、F、G.

3.完整程式碼

/************************************************************************
CSDN 勿在浮沙築高臺 http://blog.csdn.net/luoshixian099演算法導論--圖的遍歷2016年7月13日                   
************************************************************************/
#include <iostream> #include <vector> #include <queue> using namespace std; char vextex[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I' }; typedef struct VertexNode //連結串列表頭結點 { char data; struct ArcNode * firstarc; }VertexNode; typedef struct ArcNode //弧結點 { char data; struct ArcNode * nextarc; }ArcNode; ArcNode * InSertArcNode(char name) { ArcNode * p = new ArcNode; p->data = name; p->nextarc = NULL; return p; } VertexNode * AdjList()//鄰接連結串列表示法 { ArcNode * p=NULL; VertexNode * List_head = new VertexNode[9]; int count = 0; List_head[count].data = 'A'; p = List_head[count].firstarc = InSertArcNode('B'); p = p->nextarc = InSertArcNode('D'); p = p->nextarc = InSertArcNode('E'); count++; List_head[count].data = 'B'; p = List_head[count].firstarc = InSertArcNode('A'); p = p->nextarc = InSertArcNode('C'); p = p->nextarc = InSertArcNode('E'); count++; List_head[count].data = 'C'; p = List_head[count].firstarc = InSertArcNode('B'); p = p->nextarc = InSertArcNode('F'); count++; List_head[count].data = 'D'; p = List_head[count].firstarc = InSertArcNode('A'); p = p->nextarc = InSertArcNode('G'); count++; List_head[count].data = 'E'; p = List_head[count].firstarc = InSertArcNode('A'); p = p->nextarc = InSertArcNode('B'); p = p->nextarc = InSertArcNode('G'); count++; List_head[count].data = 'F'; p = List_head[count].firstarc = InSertArcNode('C'); count++; List_head[count].data = 'G'; p = List_head[count].firstarc = InSertArcNode('D'); p = p->nextarc = InSertArcNode('E'); p = p->nextarc = InSertArcNode('H'); count++; List_head[count].data = 'H'; p = List_head[count].firstarc = InSertArcNode('G'); p = p->nextarc = InSertArcNode('I'); count++; List_head[count].data = 'I'; p = List_head[count].firstarc = InSertArcNode('H'); return List_head; } void AdjMatrix(char arc[][9]) { for (int i = 0; i < 9; i++) //初始化鄰接矩陣 for (int j = 0; j < 9; j++) { arc[i][j] = 0; } arc[0][1] = arc[0][3] = arc[0][4] = 1; arc[1][0] = arc[1][2] = arc[1][4] = 1; arc[2][1] = arc[2][5] = 1; arc[3][0] = arc[3][6] = 1; arc[4][0] = arc[4][1] = arc[4][6] = 1; arc[5][2] = 1; arc[6][3] = arc[6][4] = arc[6][7] = 1; arc[7][6] = arc[7][8] = 1; arc[8][7] = 1; } void DFS_matrix(char G[][9],int i,bool *visited) //深度優先搜尋與結點i相通的所有節點 { visited[i] = true; //頂點i被訪問,標誌置為true for (int j = 0; j < 9; j++) { if (!visited[j] && G[i][j]==1) { cout << vextex[j] << ","; DFS_matrix(G, j, visited); //遞迴 } } } void DFS_AdjMatrix(char G[][9]) //深度優先搜尋_鄰近矩陣儲存 { bool visited[9] = { 0 }; //初始化訪問標誌陣列 for (int i = 0; i < 9; i++) //檢測是否所有節點都被訪問過 { if (!visited[i])//頂點i未被訪問過,結點i進行深度優先搜尋 { cout << vextex[i]<<","; DFS_matrix(G, i, visited);//深度優先搜尋頂點i } } } void DFS_list(VertexNode * GRAPH, int i, bool *visited) { visited[i] = true; //頂點i被訪問,標誌置為true cout << vextex[i] << ","; ArcNode * p = GRAPH[i].firstarc; //找到第一個鄰接連結串列結點 while (p!=NULL) { int temp = p->data - 'A'; //計算節點的位置 if (!visited[temp]) //檢測鄰接頂點是否被訪問過 DFS_list(GRAPH, temp, visited); //深度優先搜尋結點temp p = p->nextarc;//回溯到下一個鄰接頂點 } } void DFS_AdjList(VertexNode * GRAPH) //深度優先搜尋--鄰接連結串列儲存 { bool visited[9] = { 0 }; //初始化訪問標誌陣列 for (int i = 0; i < 9; i++)//檢測是否所有節點都被訪問過 { if (!visited[i]) { DFS_list(GRAPH, i, visited);//深度優先搜尋頂點i } } } void BFS_list(VertexNode *GRAPH, int i, bool *visited, queue<char> &Q) { cout << Q.front() << ","; Q.pop(); //出佇列 /*訪問到頂點i的所有鄰接點*/ ArcNode *p = GRAPH[i].firstarc; //第一個鄰結點 while ( p!=NULL ) //依次訪問頂點i的鄰接點 { /*(p->data - 'A')代表頂點的序號*/ if (*(visited + (p->data - 'A')) == 0)//檢測鄰接點是否被訪問過 { *(visited + (p->data - 'A')) = true;//訪問標誌置1 Q.push(p->data); //鄰接點加入優先佇列 } p = p->nextarc; } if (!Q.empty()) //遞迴遍歷佇列裡的頂點 { BFS_list(GRAPH, Q.front() - 'A', visited, Q); } } void BFS_AdjList(VertexNode *GRAPH)//廣度優先搜尋頂點i--鄰接表儲存 { bool visited[9] = { 0 }; //訪問標誌初始化 queue<char> Q; //優先佇列 for (int i = 0; i < 9; i++) { if (!visited[i]) { visited[i] = true; //訪問標誌置1 Q.push(vextex[i]); //進入頂點佇列 BFS_list(GRAPH, i, visited, Q); //廣度優先搜尋頂點i } } } void BFS_KLevel(VertexNode * GRAPH, int i,int k) //計算距離頂點i為k的所有頂點 { if (k==0) //如果k=0,輸出此頂點 { cout << GRAPH[i].data << endl; return; } queue<char> Q1; //已訪問頂點 queue<unsigned int> Q2; //已訪問頂點與頂點i的距離 bool visited[9] = { 0 };//訪問標誌 visited[i] = true; //頂點i置1 Q1.push(vextex[i]); //進入佇列 Q2.push(0); //距離佇列 while (!Q1.empty()) { int index = Q1.front() - 'A'; //頂點的序號 ArcNode *p = GRAPH[index].firstarc;//第一個鄰接點 int level = Q2.front(); while (p!=NULL) { if (*(visited+(p->data-'A')) == 0) //結點沒有被訪問過 { *(visited + (p->data - 'A')) =true;//訪問標誌置1 Q1.push(p->data); Q2.push(level + 1); //距離+1 if (level + 1 == k) //判斷距離 { cout << p->data << ","; } } p = p->nextarc; } Q1.pop(); Q2.pop(); } } int main() { VertexNode * GRAPH = AdjList(); //鄰接連結串列 char G[9][9] = { 0 }; AdjMatrix(G); //鄰接矩陣 DFS_AdjMatrix(G); //DFS--鄰接矩陣 cout <<" DFS--鄰接矩陣"<< endl; DFS_AdjList(GRAPH); //DFS--鄰接連結串列 cout << " DFS--鄰接連結串列" << endl; BFS_AdjList(GRAPH); //BFS--鄰接連結串列 cout << " BFS--鄰接連結串列" << endl; cout << "------------" << endl; BFS_KLevel(GRAPH,1,2);//計算距離頂點B為2的頂點 cout << " 距離頂點B為2的頂點" << endl; return 0; }

這裡寫圖片描述

Reference :
資料結構–耿國華
演算法導論-第三版