1. 程式人生 > >圖的深度優先遍歷(遞迴與非遞迴演算法)和廣度優先遍歷

圖的深度優先遍歷(遞迴與非遞迴演算法)和廣度優先遍歷

老師的題目::

實驗內容

已知某地區的公路網以圖表示,圖中的頂點表示站點,任意兩站點間的路段以帶權的邊構成的鄰接矩陣表示,矩陣中非零元表示兩個站點間存在直接的路段,否則沒有路段。

開啟E:\Test資料夾中的exp06.cpp檔案,補充編寫所需程式碼。程式首先進行圖的連通性判定,若圖連通則輸出連通訊息,否則繼續計算和輸出圖的連通分量數。

輸入資料在檔案exp06.in中,首行的整數是站點的總數n(1<n<=30);第2行開始的n行中,每行n個整數,是這n個站點構成的公路網的鄰接矩陣。例如,

6

01 3 4 9 0

10 9 9 0 0

39 0 0 6 8

49 0 0 5 7

90 6 5 0 4

00 8 7 4 0

主函式中,在呼叫讀入資料函式readData()時,會自動將矩陣中的零元(除對角線保持0以外)替換成無窮大(9999)。

Search(intv)函式實現從頂點v出發的一次搜尋過程,並累計訪問頂點數。

若圖是連通的,則輸出檔案exp06.out中包含如下文字:

All vertexsare connected.

否則,計算和輸出連通分量數,輸出檔案的內容則如下例:

    The number of connected components is 2.

解題思路

利用一次深度優先或者廣度優先搜尋過程中對訪問頂點數的計數,並判斷其與圖的頂點總數是否相等來判定圖的連通性。

如果圖不連通,則繼續從下一個未被訪問的頂點出發再進行一次搜尋,如此反覆,直到已遍歷圖的所有頂點,累計的搜尋次數即是圖的連通分量數。

我在程式碼中都做了註解

#include <iostream>
#include <stdio.h>
using namespace std;

const int Size=30;
const double INF=9999;		// infinity (無窮大)
int vexnum;					// total number of vertex (頂點總數) 
int adjmat[Size][Size];		// adjacent matrix (鄰接矩陣)
int mark[Size];				// vector of visiting mark of vertex (頂點訪問標記向量)
int visitnum;				// number of visited vertex for one search (一次搜尋中被訪問頂點數)
int adjnum;					// number of connected components (連通分量數) 

void readData()
{	int i,j;
	cin>>vexnum;			// input vexnum 
	for(i=0; i<vexnum; i++)
		for(j=0; j<vexnum; j++)
		{	cin>>adjmat[i][j];
			if(i!=j && adjmat[i][j]==0) adjmat[i][j]=INF;
		}
}
/*int first_adj(int v){
	int w;
	for(w=0;w<vexnum;w++)
		if(adjmat[v][w]!=INF||v!=w) return w;
	return -1;	
}
int next_adj(int v,int w){
	for(w+=1;w<vexnum;w++)
		if(adjmat[v][w]!=INF||v!=w) return w;
	return -1;	
}*/
void Search(int v)			// one time search, v represents the starting vertex
{//************************************************
	//********************************************
	/*int w=-1;   //書上的解法,太麻煩了
	mark[v]=1;
	visitnum++;
	w=first_adj(v);
	while(w!=-1){
		if(!mark[w])
			Search(w);
		w=next_adj(v,w);
	}*/
	//==============================================
	

	//**************************************************
	/*遞迴的深度優先搜尋
	int i;
	if(mark[v]==1) return;   //訪問過了,要有,可用於判斷連通分量
	mark[v]=1;   //否則訪問他
	visitnum++;
	for(i=0;i<vexnum;i++){
		if(adjmat[v][i]!=INF&&v!=i&&mark[i]!=1)   //找到未訪問過的鄰接點
			Search(i);
	}
	return;*/
	//====================================================





	//***************************************************
	/*
	//非遞迴的深度優先搜尋
	int *stack=new int[vexnum],top=-1,w;
	if(mark[v]==1) return;
	stack[++top]=v;
	mark[v]=1;
	visitnum++;
	while(top!=-1){
		v=stack[top];         //不能top--,因為後面還要用到此處節點
		for(w=0;w<vexnum;w++){//找一個未訪問的鄰接點,可以使用上面的first_adj(v)
			if(adjmat[v][w]!=INF && v!=w && mark[w]!=1)
				break;
		}
		if(w==vexnum) top--;  //此節點   沒有   還沒找過的鄰接點了,退棧
		else{					//有未訪問鄰接點,人棧,接下來從這個節點繼續深度訪問
			stack[++top]=w;	
			mark[w]=1;
			visitnum++;
		}
	}
	*/
	//=====================================================


	//*******************************************
	/*
	//廣度優先搜尋   先訪問再入隊
	int *queue=new int[vexnum+1],front=0,rear=0;
	int w;
	if(mark[v]==1) return;   
	mark[v]=1;	
	visitnum++;
	queue[rear++]=v;
	while(front!=rear){
		v=queue[front++];
		for(w=0;w<vexnum;w++){   //找到所有未訪問鄰接點入隊
			if(adjmat[v][w]!=INF&&v!=w&&mark[w]!=1){
				queue[rear++]=w;
				mark[w]=1;
				visitnum++;
			}
		}
		//找完了
	}
	//========================================
	*/
 //================================================
}

int main()
{	int i;
/*	freopen("exp06.in", "r", stdin);
	freopen("exp06.out", "w", stdout);*/
	readData();							// input data 
	for(i=0; i<vexnum; i++) mark[i]=0;	// initialze the visiting mark
	visitnum=0;
	Search(0);							// one time search from vertex 0 
	if(visitnum==vexnum) cout<<"All vertexs are connected.\n";
	else 
	{	adjnum=1;
		//************************************************
	for(i=0;i<vexnum;i++){
		if(!mark[i]){
			Search(i);
			adjnum++;
		}
	}
 		//================================================
		cout<<"The number of connected components is "<<adjnum<<".\n";
	}
	return 0;
}