《資料結構與演算法設計》實驗報告書之圖的遍歷操作
《資料結構與演算法設計》實驗報告書之圖的遍歷操作
實驗專案
圖的遍歷操作
實驗目的
掌握有向圖和無向圖的概念;掌握鄰接矩陣和鄰接連結串列建立圖的儲存結構;掌握DFS及BFS對圖的遍歷操作;瞭解圖結構在人工智慧、工程等領域的廣泛應用。
實驗內容
採用鄰接矩陣和鄰接連結串列其中一種作為圖的儲存結構,完成有向圖和無向圖的DFS和BFS操作。
演算法設計分析
(一)資料結構的定義
圖遍歷又稱圖的遍歷,屬於資料結構中的內容。指的是從圖中的任一頂點出發,對圖中的所有頂點訪問一次且只訪問一次。圖的遍歷操作和樹的遍歷操作功能相似。圖的遍歷是圖的一種基本操作,圖的許多其它操作都是建立在遍歷操作的基礎之上。
由於圖結構本身的複雜性,所以圖的遍歷操作也較複雜,主要表現在以下四個方面:
① 在圖結構中,沒有一個“自然”的首結點,圖中任意一個頂點都可作為第一個被訪問的結點。
② 在非連通圖中,從一個頂點出發,只能夠訪問它所在的連通分量上的所有頂點,因此,還需考慮如何選取下一個出發點以訪問圖中其餘的連通分量。
③ 在圖結構中,如果有迴路存在,那麼一個頂點被訪問之後,有可能沿迴路又回到該頂點。
④ 在圖結構中,一個頂點可以和其它多個頂點相連,當這樣的頂點訪問過後,存在如何選取下一個要訪問的頂點的問題。
圖的儲存結構定義為鄰接矩陣:
/*定義圖儲存結構*/
#define maxn 500 // 圖中頂點數
#define maxe 1000 // 圖中邊數
typedef struct{
int v[maxn+1]; // 存放頂點資訊
int arcs[maxn+1][maxn+1]; // 鄰接矩陣
}graph;
(二)總體設計
實驗總共包括六個函式:主函式,無向圖的建立函式,有向圖的建立函式,DFS遍歷函式,BFS遍歷演算法函式,列印鄰接矩陣函式。
主函式:統籌呼叫各個函式以實現相應功能
Int main()
void execute()
無向圖的建立函式:建立無向圖的鄰接矩陣
void creatadi(graph &g,int n,int e)
有向圖的建立函式:建立有向圖的鄰接矩陣
void creatadj(graph &g,int n,int e)
DFS遍歷函式:利用深度優先遍歷圖的方法遍歷圖
void DFS1(int cur,graph &g,int n)
BFS遍歷函式:利用廣度優先遍歷圖的方法遍歷圖
void BFS1(graph &g,int n)
列印鄰接矩陣函式:利用遍歷鄰接矩陣的方法列印圖
void printArr(graph &g,int n,int e)
(三)各函式的詳細設計:
主函式main()
主要就是進行功能的實現。
無向圖的建立函式void creatadi(graph &g,int n,int e):
建立無向圖的鄰接矩陣,由於無向圖是對稱的,所以鄰接矩陣是對稱的。
有向圖的建立函式void creatadj(graph &g,int n,int e):
建立有向圖的鄰接矩陣,由於有向圖是單邊的,所以鄰接矩陣是不對稱的。
DFS遍歷函式void DFS1(int cur,graph &g,int n) :
利用深度優先遍歷圖的方法遍歷圖,主要是通過遞迴來一個一個頂點找過去,走過的標記一下,沒路了在回去找。
BFS遍歷函式void BFS1(graph &g,int n):
利用廣度優先遍歷圖的方法遍歷圖,主要運用了佇列的結構,將與該頂點有聯絡的都放進佇列,之後再把佇列裡面的值打印出來。
列印鄰接矩陣函式void printArr(graph &g,int n,int e):
利用遍歷鄰接矩陣的方法列印圖
實驗測試結果
無向圖建立以及結果:
有限圖建立以及結果:
實驗總結:(100字到200字)
此部分附上主要程式程式碼和相關的註釋說明、除錯資料及過程、問題及解決辦法。 (最重要)
(1)除錯過程中主要遇到哪些問題?是如何解決的?
答:在建立圖的儲存結構的時候還是遇見過一些問題的,陣列開的太大,導致程式無法執行,還有就是圖的遍歷這一塊地方,BFS這個通過佇列來放資料時,出現過一點小問題,不過問題不是很大,能夠自己解決。
(2)經驗和體會
答:還是那句老話,多敲程式碼自己練習,有時間把多複習多上網查查資料,增加自己對圖的遍歷的理解。
附錄 實驗程式程式碼(該部分請加註釋)
/picture.h函式程式碼/
#define maxn 500 // 圖中頂點數
#define maxe 1000 // 圖中邊數
typedef struct{
int v[maxn+1]; // 存放頂點資訊
int arcs[maxn+1][maxn+1]; // 鄰接矩陣
}graph;
//無向圖的鄰接矩陣
void creatadi(graph &g,int n,int e)
{
int i, j, k;
for (i=1; i<=n; i++ )
for (j=1; j<=n; j++)
g.arcs[i][j]=0;
for (k=1; k<=e; k++)
{
std::cout<<"第"<<k<<"條邊的位置:"<<endl;
std::cin>>i>>j; //輸入一條邊(i,j)
g.arcs[i][j] = 1;
g.arcs[j][i] = 1;
}
}
//有向圖的鄰接矩陣
void creatadj(graph &g,int n,int e)
{
int i, j, k;
for (i=1; i<=n; i++ )
for (j=1; j<=n; j++)
g.arcs[i][j] = 0;
for (k=1; k<=e; k++)
{
std::cout<<"第"<<k<<"條邊的位置:"<<endl;
std::cin>>i>>j; //輸入一條弧<i,j>
g.arcs[i][j] = 1;
}
}
void printArr(graph &g,int n,int e){
int i,j;
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
cout<<g.arcs[i][j]<<" ";
}
cout<<endl;
}
}
//深度優先遍歷無向圖
void DFS1(int cur,graph &g,int n){
std::cout<<cur<<" ";
sum++;
if(sum == n){
return ;
}
int i;
for(i=1;i<=n;i++){
if(g.arcs[cur][i] == 1 && g.v[i] == 0){
g.v[i] = 1;
DFS1(i,g,n);
}
}
}
//廣度優先遍歷無向圖
void BFS1(graph &g,int n){
int head = 1,tail = 1,i,cur;
que[tail] = 1;
tail++;
g.v[1] = 1;
while(head < tail && tail <= n){
cur = que[head];
for(i=1;i<=n;i++){
if(g.arcs[cur][i] == 1 && g.v[i] == 0){
que[tail] = i;
tail++;
g.v[i] = 1;
}
if(tail > n){
break;
}
}
head++;
}
for(i=1;i<=n;i++)
std::cout<<que[i]<<" ";
std::cout<<std::endl;
}
/menu.h選單函式程式碼/
void menu(){
std::cout<<"\n";
std::cout<<" ************************圖的應用************************\n";
std::cout<<" * *\n";
std::cout<<" * a:建立無向圖的鄰接矩陣 b:建立有向圖的鄰接矩陣 *\n";
std::cout<<" * c:DFS遍歷 d:BFS遍歷 *\n";
std::cout<<" * g:退出程式 *\n";
std::cout<<" * *\n";
std::cout<<" ********************************************************\n";
}
/主函式程式碼/
#include <iostream>
using namespace std;
int sum = 0,que[10001];
#include "menu.h"
#include "picture.h"
int main()
{
void execute();
execute();
return 0;
}
void execute()
{
for(;;)
{
menu();
graph s;
char a;
int n,e;
cin>>a;
switch(a)
{
case 'a':
cout<<"請輸入頂點個數:"<<endl;
cin>>n;
cout<<"請輸入邊的個數:"<<endl;
cin>>e;
creatadi(s,n,e);
printArr(s,n,e);
break;
case 'b':
cout<<"請輸入頂點個數:"<<endl;
cin>>n;
cout<<"請輸入邊的個數:"<<endl;
cin>>e;
creatadj(s,n,e);
printArr(s,n,e);
break;
case 'c':
cout<<"該圖DFS遍歷為:"<<endl;
for(int k=1;k<=n;k++)
s.v[k] = 0;
s.v[1] = 1;
DFS1(1,s,n);
break;
case 'd':
cout<<"該圖BFS遍歷為:"<<endl;
for(int k=1;k<=n;k++)
s.v[k] = 0;
BFS1(s,n);
break;
case 'e':
cout<<" 再見!"<<endl;
return ;
default:
cout<<"輸入的字元有誤,請重新輸入!!"<<endl;
break;
}
}
}