1. 程式人生 > >《資料結構與演算法設計》實驗報告書之圖的遍歷操作

《資料結構與演算法設計》實驗報告書之圖的遍歷操作

《資料結構與演算法設計》實驗報告書之圖的遍歷操作

實驗專案
圖的遍歷操作

實驗目的
掌握有向圖和無向圖的概念;掌握鄰接矩陣和鄰接連結串列建立圖的儲存結構;掌握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;
		}
	}
}