資料結構:圖的遍曆--深度優先、廣度優先,--廣度

來源:互聯網
上載者:User

資料結構:圖的遍曆--深度優先、廣度優先,--廣度

                       圖的遍曆:深度優先、廣度優先

遍曆

    圖的遍曆是指的某一頂點出發,按照一定的策略訪問圖中的每一個頂點。當然,每個頂點有且只能被訪問一次。

    在圖的遍曆中,深度優先和廣度優先是最常使用的兩種遍曆方式。這兩種遍曆方式對無向圖和有向圖都是適用的,並且都是從指定的頂點開始遍曆的。先看下兩種遍曆方式的遍曆規則:

深度優先

    深度優先遍曆也叫深度優先搜尋(Depth First Search)。它的遍曆規則:不斷地沿著頂點的深度方向遍曆。頂點的深度方向是指它的鄰接點方向。

    具體點,給定一圖G=<V,E>,用visited[i]表示頂點i的訪問情況,則初始情況下所有的visited[i]都為false。假設從頂點V0開始遍曆,則下一個遍曆的頂點是V0的第一個鄰接點Vi,接著遍曆Vi的第一個鄰接點Vj,……直到所有的頂點都被訪問過。

    所謂的第一個是指在某種儲存結構中(鄰接矩陣、鄰接表),所有鄰接點中儲存位置最近的,通常指的是下標最小的。在遍曆的過程中有兩種情況經常出現

看一個例子
從V0開始遍曆    遍曆分析:V0有兩個鄰接點V1和V2,選擇下標最小的V1遍曆。接著從V1開始深度遍曆,V1隻有鄰接點V3,也就是沒有選的:遍曆V3。接著從V3開始遍曆,V3隻有鄰接點V0,而V0已經被遍曆過。此時出現了上面提到的情況一,開始回溯V1,V1無未被遍曆的鄰接點,接著回溯V0,V0有一個未被遍曆的鄰接點V2,新的一輪深度遍曆從V2開始。V2無鄰接點,且無法回溯。此時出現了情況二,檢測visited[i],只有V4了。深度遍曆完成。看到回溯,應該可以想到需要使用棧。遍曆序列是V0->V1->V3->V2->V4。從其它頂點出發的深度優先遍曆序列是:V1->V3->V0->V2->V4。V2->V0->V1->V3->V4。
V3->V0->V1->V2->V4。
V4->V2->V0->V1->V3。
以上結果,我們稍後用於測試程式。
結合在圖的實現:鄰接矩陣中的代碼,我們看下在鄰接矩陣形式下的圖的深度遍曆演算法:深度優先代碼
/*深度優先搜尋從vertex開始遍曆,visit是遍曆頂點的函數指標*/void Graph::dfs(int vertex, void (*visit)(int)){stack<int> s;//visited[i]用於標記頂點i是否被訪問過bool *visited = new bool[numV];//count用於統計已遍曆過的頂點數int i, count;for (i = 0; i < numV; i++)visited[i] = false;count = 0;while (count < numV){visit(vertex);visited[vertex] = true;s.push(vertex);count++;if (count == numV)break;while (visited[vertex]){for (i = 0; i < numV&& (visited[i] || matrix[vertex][i] == 0 || matrix[vertex][i] == MAXWEIGHT); i++);if (i == numV)  //當前頂點vertex的所有鄰接點都已訪問完了{if (!s.empty()){s.pop();   //此時vertex正是棧頂,應先出棧if (!s.empty()){vertex = s.top();s.pop();}else  //若棧已空,則需從頭開始尋找新的、未訪問過的頂點{for (vertex = 0; vertex < numV && visited[vertex]; vertex++);}}else  //若棧已空,則需從頭開始尋找新的、未訪問過的頂點{for (vertex = 0; vertex < numV && visited[vertex]; vertex++);}}else  //找到新的頂點應更新當前訪問的頂點vertexvertex = i;}}delete[]visited;}
其它代碼前面已經見過,就不給出了,下面看的廣度遍曆。深度遍曆和廣度遍曆的測試,稍後一併給出。
廣度優先    廣度優先遍曆也叫廣度優先搜尋(Breadth First Search)。它的遍曆規則:    具體點,給定一圖G=<V,E>,用visited[i]表示頂點i的訪問情況,則初始情況下所有的visited[i]都為false。假設從頂點V0開始遍曆,且頂點V0的鄰接點下表從小到大有Vi、Vj...Vk。按規則1,接著應遍曆Vi、Vj和Vk。再按規則2,接下來應遍曆Vi的所有鄰接點,之後是Vj的所有鄰接點,...,最後是Vk的所有鄰接點。接下來就是遞迴的過程...在廣度遍曆的過程中,會出現圖不連通的情況,此時也需按上述情況二來進行:測試visited[i]...。在上述過程中,可以看出需要用到隊列。
舉個例子,還是同樣一幅圖:
從V0開始遍曆    遍曆分析:V0有兩個鄰接點V1和V2,於是按序遍曆V1、V2。V1先於V2被訪問,於是V1的鄰接點應先於V2的鄰接點被訪問,那就是接著訪問V3。V2無鄰接點,只能看V3的鄰接點了,而V0已被訪問過了。此時需檢測visited[i],只有V4了。廣度遍曆完畢。
遍曆序列是
V0->V1->V2->V3->V4。從其它頂點出發的廣度優先遍曆序列是V1->V3->V0->V2->V4。V2->V0->V1->V3->V4。
V3->V0->V1->V2->V4。
V4->V2->V0->V1->V3。
以上結果,我們同樣用於測試程式。

在鄰接矩陣下,圖的廣度遍曆演算法廣度優先代碼
/*廣度優先搜尋從vertex開始遍曆,visit是遍曆頂點的函數指標*/void Graph::bfs(int vertex, void(*visit)(int)){//使用隊列queue<int> q;//visited[i]用於標記頂點i是否被訪問過bool *visited = new bool[numV];//count用於統計已遍曆過的頂點數int i, count;for (i = 0; i < numV; i++)visited[i] = false;q.push(vertex);visit(vertex);visited[vertex] = true;count = 1;while (count < numV){if (!q.empty()){vertex = q.front();q.pop();}else{for (vertex = 0; vertex < numV && visited[vertex]; vertex++);visit(vertex);visited[vertex] = true;count++;if (count == numV)return;q.push(vertex);}//代碼走到這裡,vertex是已經訪問過的頂點for (int i = 0; i < numV; i++){if (!visited[i] && matrix[vertex][i] > 0 && matrix[vertex][i] < MAXWEIGHT){visit(i);visited[i] = true;count ++;if (count == numV)return;q.push(i);}}}delete[]visited;}

結合兩種遍曆的代碼,我們對同一幅圖進行測試,它的主函數是
void visit(int vertex){cout << setw(4) << vertex;}int main(){cout << "******圖的遍曆:深度優先、廣度優先***by David***" << endl;bool isDirected, isWeighted;int numV;cout << "建圖" << endl;cout << "輸入頂點數 ";cin >> numV;cout << "邊是否帶權值,0(不帶) or 1(帶) ";cin >> isWeighted;cout << "是否是有向圖,0(無向) or 1(有向) ";cin >> isDirected;Graph graph(numV, isWeighted, isDirected);cout << "這是一個";isDirected ? cout << "有向、" : cout << "無向、";isWeighted ? cout << "有權圖" << endl : cout << "無權圖" << endl;graph.createGraph();cout << "列印鄰接矩陣" << endl;graph.printAdjacentMatrix();cout << endl;cout << "深度遍曆" << endl;for (int i = 0; i < numV; i++){graph.dfs(i, visit);cout << endl;}cout << endl;cout << "廣度遍曆" << endl;for (int i = 0; i < numV; i++){graph.bfs(i, visit);cout << endl;}system("pause");return 0;}

運行


仔細對照測試結果,我們的代碼是沒有問題的。
完整代碼下載:圖的遍曆:深度優先、廣度優先
小結對於某個圖來說,深度優先遍曆和廣度優先遍曆的序列不是唯一的,但當圖的儲存結構一確定,它的遍曆序列就是唯一的。因為當有多個候選點時,我們總是優先選擇下標最小的。

轉載請註明出處,本文地址:http://blog.csdn.net/zhangxiangdavaid/article/details/38323633
若有所協助,頂一個哦!
專欄目錄:資料結構與演算法目錄



資料結構:圖的廣度優先遍曆與深度優先遍曆

圖的深度優先遍曆:1->2->4->6->5->3
圖的廣度優先遍曆:1->2->3->4->5->6
另外這個問題別人問過了。。。。
 
資料結構:圖的深度優先遍曆與廣度優先遍曆

圖的深度優先遍曆:1->2->4->6->5->3
圖的廣度優先遍曆:1->2->3->4->5->6
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.