深度優先搜尋和廣度優先搜尋

來源:互聯網
上載者:User

 將圖記為G(V,E)。圖的表示一般有兩種方法:鄰接矩陣和鄰接表。鄰接矩陣是一個為|V|*|V|的二維矩陣,記為array,array[i][j]表示節點i和節點j之間是否存在邊,對於帶權圖(又稱為網),array[i][j]還可以表示節點i和節點j之間邊的權。因為鄰接矩陣大小和圖中的邊數|E|無關,所以鄰接矩陣更適合於稠密圖(|E|接近|V|²)。鄰接矩陣同樣適合程式需要經常判斷兩個頂點之間是否存在邊的情形。而圖通常採用鄰接表表示,因為對鄰接表稍作修改就可以用於各種圖的變體,因而有很好的適應性。鄰接表標記法對圖中的每個頂點都維護一條鏈表,鏈表中儲存的是以該頂點為弧尾(起點)的邊的資訊。對於有向圖,鄰接表大小為|E|,無向圖的鄰接表大小為2|E|。所以鄰接表所需儲存空間為O(V+E)。

圖的基本操作有如下幾種:加入(刪除)頂點、加入(刪除)邊,取頂點,求鄰接點,求節點的度,圖的遍曆。除了遍曆演算法,其他動作都比較簡單,所以說說遍曆就好了,這也是很多其他圖演算法的基礎。

圖按是否有向分為:有向圖、無向圖;按是否帶權分為無權圖、帶全圖(網)。按這兩種標準組合可得四種圖類型,定義為下面的枚舉類型:

enum Graph_Type{ DG, DN, UG, UN };

先給出邊類型,頂點類型,圖類型的定義:

//VertexType表示頂點值的類型,CostType表示邊的權的類型,

template< typename VertexType, typename CostType  >class Edge{friend class Graph<VertexType, CostType >;public:Edge( int sv, int ev, CostType  cost, Edge<VertexType, CostType > *next ):start_vertex( sv ), end_vertex( ev ), cost( cost ), next_adj( next ){}private:int start_vertex;//起始節點編號int end_vertex;//終結點編號CostType  cost;//邊的權Edge<VertexType, CostType > *next_adj;};template< typename VertexType, typename CostType > class Vertex{friend class Graph<VertexType, CostType>;public:Vertex(VertexType va, int sn, Edge<VertexType, CostType > *fa, int p ):value(va), serial_number( sn ), first_adj( fa ),parent(p){}private:VertexType  value;//頂點值int serial_number;//頂點編號Edge<VertexType,CostType> *first_adj;int parent;//用於產生各種產生樹,};/* *之前沒有注意到圖中的節點的實值型別和邊的權值的類型是不一樣的 *如果只有一個型別參數,那麼這個圖就不實用了. */template< typename VertexType, typename CostType >class Graph{public:Graph( int vex_num, int edge_num,vector<VertexType>& value, vector<int> begin_vex,vector<int> end_vex,vector<CostType>& cost,Graph_Type gt );void BreadthFirstSearch( int i );//從節點i開始進行廣度優先搜尋。void DepthFirstSearch( );private:vector< Vertex<VertexType, CostType> > vertex_table;//頂點數組int vex_num;//頂點數int edge_num;//邊數Graph_Type gtype;//圖類型};

先搞清圖的遍曆的含義:指從圖的任一頂點出發,對圖中每個頂點訪問一次且只訪問一次。圖的遍曆演算法有兩種,一種是深度優先遍曆,一種是廣度優先遍曆。

先說前者。深度優先遍曆的基本思想就是從某個源頂點v出發,沿著以它為起點(尚未探測過)的邊(v,w),如果w已經訪問過,則另選一條從v出發的尚未探測過的邊。否則,訪問w,然後從w開始搜尋,直至搜尋完從w出發的所有路徑,即訪問完所有從w出發可達的頂點,最後回溯到頂點v,再從v出發,探測尚未探測過的邊,直至所有從v出發的邊都探測過為止。如果還存在未被訪問的頂點,則重複以上過程,直至所有的頂點都被訪問過為止。

演算法描述起來還是挺麻煩的啊。從描述中可以看出,我們需要使用一個輔助數組visited,用以記錄頂點是否被訪問過。另外,深度優先演算法有點類似於樹的先根遍曆。

template< typename VertexType, typename CostType >void Graph<VertexType, CostType>::DepthFirstSearch(){vector<bool> visited( vex_num, false );clear_vex_parent();for( int j = 0; j < vex_num; ++j ){if( visited[j] == false ){DepthFirstSearch( j+1, visited );}}}template< typename VertexType, typename CostType >void Graph<VertexType, CostType>::DepthFirstSearch( int i, vector<bool> &visited ){int index; visited[i-1] = true;Vertex<VertexType, CostType> *vex = &this->vertex_table[i-1];Edge<VertexType, CostType> *edge = vex->first_adj;while( edge != NULL ){index = edge->end_vertex;if( visited[index-1] == false ){this->vertex_table[index-1].parent = i;DepthFirstSearch( index, visited );}edge = edge->next_adj;}}

再看廣度優先搜尋。

從源頂點v出發,依次探測所有從v出發的所有邊,訪問v的所有鄰接點w1,w2,···,

wn,然後再依次訪問與w1,w2,···,wn鄰接的所有未訪問過的頂點,直至圖中所有和v路徑相通的頂點都已被訪問,如果圖中存在尚未訪問的頂點,則重複上述過程,直至圖中所有頂點都已被訪問過。圖的廣度優先搜尋類似於樹的層次遍曆,需要使用隊列作為輔助的資料結構,另外,和深度優先搜尋一樣,需要一個visited數組記錄頂點是否被訪問過。

兩個演算法的時間複雜度都是O(V+E),二者實際上都是遍曆了一遍鄰接表而已,只是方式不同罷了。

template< typename VertexType, typename CostType >void Graph<VertexType, CostType>::BreadthFirstSearch( int i ){vector<bool> visited( vex_num, false );queue< Vertex<VertexType, CostType>* > vertex_queue;vertex_queue.push( &vertex_table[i-1] );//添加到隊尾visited[ i-1 ] = true;int visitedNumber = 1;clear_vex_parent();while( visitedNumber != vex_num ){while( !vertex_queue.empty() ){Vertex<VertexType, CostType> *vertex = vertex_queue.front();vertex_queue.pop();//刪除隊頭.Vertex<VertexType, CostType> *adj_vex;Edge<VertexType, CostType> *edge = vertex->first_adj;while( edge != NULL ){int serial_number = edge->end_vertex;adj_vex = &vertex_table[serial_number-1];if( !visited[serial_number-1] )//如果尚未訪問.{vertex_queue.push( adj_vex ); adj_vex->parent = vertex->serial_number;//設定新排入佇列的節點的父母:。visited[serial_number-1] = true;++visitedNumber;}edge = edge->next_adj;}}//while//如果圖為非連通圖,則需要從多個源點開始進行廣度優先搜尋才能確保搜尋到圖中的每個節點.for( int j = 0; j < vex_num; ++j )if( visited[j] == false ){vertex_queue.push( &(vertex_table[j]) );++visitedNumber;visited[j] = true;break;}}}

聯繫我們

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