對無向圖進行鄰接矩陣的轉化,并且利用DFS(深度優先)和BFS(廣度優先)算法進行遍歷輸出, 在鄰接矩陣存儲結構上,完成最小生成樹的操作。

一 實驗目的

1.掌握圖的相關概念。

2.掌握用鄰接矩陣和鄰接表的方法描述圖的存儲結構。

3.掌握圖的深度優先搜索和廣度優先搜索遍歷的方法及其計算機的實現。

4.理解最小生成樹的有關算法

二 實驗內容及要求

實驗內容:

選擇鄰接矩陣或鄰接鏈表存儲結構,掌握圖的創建、遍歷、最小生成樹、拓撲排序、關鍵路徑、最短路徑等典型操作。

編程實現如下功能:

(1)輸入無向圖的頂點數、邊數及各條邊的頂點對,建立用鄰接矩陣表示的無向圖。

(2)對圖進行深度優先搜索和廣度優先搜索遍歷,并分別輸出其遍歷序列。

(3)在鄰接矩陣存儲結構上,完成最小生成樹的操作。

實驗要求:

1.鍵盤輸入數據;

2.屏幕輸出運行結果。

3.要求記錄實驗源代碼及運行結果。

4.運行環境:CodeBlocks/Dev c++/VC6.0等C編譯環境

三 實驗過程及運行結果

實驗一:對無向圖進行鄰接矩陣的轉化,并且利用DFS和BFS算法進行遍歷輸出, 在鄰接矩陣存儲結構上,完成最小生成樹的操作。

一 算法設計思路

包含七個功能函數和一個主函數:void initialMatrix(Graph *g,int n)、void CreatMatrix(Graph *g,int startPoint,int endPoint)、void InputEdge(Graph* g, int n)、void OutputMatrix(Graph g,int n)、void DFSTravers(Graph &g,int i)、void BFSTraverse(Graph &g)、void primMST(Graph* graph)

void initialMatrix(Graph *g,int n):這個函數是一個用于初始化圖的鄰接矩陣的函數。使用兩個嵌套的循環遍歷鄰接矩陣的每個元素。在每次循環中,將矩陣中的元素賦值為 0,表示該位置上的邊不存在。在外層循環中,將圖結構中的頂點數組 g->vex 的每個元素賦值為 1,表示該頂點存在。

void CreatMatrix(Graph *g,int startPoint,int endPoint):這段函數是一個用于創建圖的鄰接矩陣的函數。將鄰接矩陣中起始頂點 startPoint 和結束頂點 endPoint 所對應的位置的元素賦值為它們之間的絕對值差,即 abs(startPoint - endPoint)。這個值可以表示邊的權值或距離。由于是無向圖,所以將鄰接矩陣中結束頂點 endPoint 和起始頂點 startPoint 所對應的位置的元素也賦值為相同的絕對值差。將圖結構中的邊數 g->numEdges 加一,表示添加了一條新的邊。

void InputEdge(Graph* g, int n):這段函數是用于輸入圖的邊并創建鄰接矩陣的函數聲明兩個整型變量 startPoint 和 endPoint,用于存儲輸入的邊的起始頂點和結束頂點。使用一個循環,循環次數為邊的數量 n。在每次循環中,通過輸入操作獲取用戶輸入的起始頂點和結束頂點,分別存儲到 startPoint 和 endPoint 變量中。調用 CreatMatrix 函數,將起始頂點和結束頂點作為參數傳遞給 CreatMatrix 函數,并將它們減去 1,以適應數組從 0 開始的索引。CreatMatrix 函數會根據傳入的起始頂點和結束頂點,在鄰接矩陣中設置相應的邊。

void OutputMatrix(Graph g,int n):這段函數是用于輸出圖的鄰接矩陣的函數輸出一行提示信息,告訴用戶接下來要輸出圖的鄰接矩陣。使用兩個嵌套的循環,外層循環控制行數,內層循環控制列數,循環次數均為圖的頂點數量 n。在每次循環中,通過cout 語句輸出圖結構中鄰接矩陣的第 i 行第 j 列的元素,即 g.matrix[i][j]。在每行輸出完畢后,通過cout 語句輸出換行符 \n,使下一行的輸出從新的一行開始。

void DFSTravers(Graph &g,int i):這段函數是用于實現深度優先搜索(DFS)遍歷圖的函數。

首先判斷頂點表中下標為 i 的頂點是否已經被遍歷,通過檢查 g.vex[i] 的值是否為 1 來判斷。如果頂點未被遍歷,則將 g.vex[i] 的值賦為 0,表示該頂點已被遍歷。使用一個循環,循環次數為圖的頂點數量 g.numVertices。在每次循環中,判斷從頂點 i 到頂點 j 是否存在邊,通過檢查 g.matrix[i][j] 的值是否大于 0 來判斷。如果存在邊,則遞歸調用 DFSTravers 函數,以頂點 j 作為新的起始頂點,繼續深度優先搜索遍歷。在遍歷完所有與頂點 i 相鄰的頂點后,通過 cout 語句輸出頂點 i 的值加 1,表示遍歷到了頂點 i。由于 DFS 是遞歸的過程,所以在遍歷完當前頂點后,會回溯到上一個頂點,繼續遍歷下一個未被遍歷的相鄰頂點。

void BFSTraverse(Graph &g):這段函數是用于實現廣度優先搜索(BFS)遍歷圖的函數。

聲明一個數組 a 用于模擬隊列,初始化為全零。

聲明兩個計數器變量 countA 和 count,分別用于記錄遍歷次數和隊列的索引。

聲明一個標志變量 flag,用于判斷某個頂點是否已經出現過。

使用一個外層循環,循環條件為 countA < g.numVertices-1,即直到遍歷完所有頂點。

在每次循環中,使用一個內層循環,循環次數為圖的頂點數量 g.numVertices。

在內層循環中,首先判斷從隊列中當前索引位置 a[count] 到頂點 j 是否存在邊,通過 g.matrix[a[count]][j] 的值是否大于 0 來判斷。

如果存在邊,則使用一個額外的循環遍歷隊列 a,判斷頂點 j 是否已經在隊列中出現過。

如果頂點 j 之前未出現過,則將其添加到隊列中,即 a[++countA] = j。

在遍歷完當前頂點的所有相鄰頂點后,將 count 自增,繼續下一輪循環。循環結束后,使用一個循環輸出隊列 a 中的頂點,表示廣度優先搜索的遍歷順序。

void primMST(Graph* graph):這個函數用于實現 Prim 算法求解最小生成樹的函數

首先聲明并初始化一些輔助數組和變量,包括 selected 數組用于標記頂點是否被選擇,parent 數組用于記錄頂點的父節點,minWeight 數組用于記錄頂點到最小生成樹的邊的權重,totalWeight 變量用于記錄最小生成樹的總權重。

然后初始化 minWeight 數組,將所有頂點的初始權重設為無窮大(INT_MAX),表示初始狀態下都不與最小生成樹相連。

接著將起始頂點的權重設為 0,表示該頂點為最小生成樹的起點。

然后使用一個循環,循環次數為圖的頂點數量減 1(因為最小生成樹有 n-1 條邊)。在每次循環中,找到權重最小的未選擇頂點(即 minWeight 數組中最小的值),記錄其索引為 minIndex。將該頂點標記為已選擇,并將其權重加到 totalWeight 中。遍歷所有未選擇的頂點,如果存在一條邊連接到該頂點且權重小于該頂點的當前最小權重,則更新該頂點的父節點為 minIndex,并更新其最小權重為邊的權重。

循環結束后,輸出最小生成樹的邊和總權重。

二 源程序代碼

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <iostream>using namespace std;
/*對無向圖進行鄰接矩陣的轉化,并且利用DFS和BFS算法進行遍歷輸出,
在鄰接矩陣存儲結構上,完成最小生成樹的操作。*/
#define MAX_VERTICES 100
typedef struct Graph
{int vex[MAX_VERTICES] = { 0 };//頂點表 0為初始值,沒這個頂點int matrix[MAX_VERTICES][MAX_VERTICES];//鄰接矩陣int numVertices;//頂點數int numEdges;//邊數} Graph;
void initialMatrix(Graph *g,int n)//初始化矩陣,賦值為0
{for (int i = 0; i < n; i++){for (int j = 0; j < n; j++){g->matrix[i][j] = 0;//數組從0開始}g->vex[i] = 1;//1代表有這個頂點}
}
void CreatMatrix(Graph *g,int startPoint,int endPoint)//創建鄰接矩陣
{g->matrix[startPoint][endPoint] = abs(startPoint-endPoint);g->matrix[endPoint][startPoint] = abs(startPoint-endPoint);//權值g->numEdges++;
}
void InputEdge(Graph* g, int n)//輸入相應邊
{int startPoint, endPoint;for (int i = 0; i < n; i++){cin >> startPoint;cin >> endPoint;CreatMatrix(g, startPoint-1, endPoint-1);}}void OutputMatrix(Graph g,int n)//輸出鄰接矩陣
{cout << "以下是圖的鄰接矩陣" << endl;for (int i = 0; i < n; i++){for (int j = 0; j < n; j++){cout << g.matrix[i][j]<<" ";}cout << "\n";}
}void DFSTravers(Graph &g,int i)//從下標為0的點開始遍歷
{//先從第一個點開始遍歷,向任意一個方向進行遍歷//遍歷一個節點后將頂點表賦值為已遍歷//如果遍歷后的頂點無后續未遍歷的頂點則輸出,然后退回到上一個節點//由上一個節點的另外一個下一個節點開始遍歷依次遞歸if (g.vex[i] == 1)//說明此點未被遍歷{g.vex[i] = 0;for (int j = 0; j < g.numVertices; j++)//從0結點向后遍歷{if (g.matrix[i][j] >0){DFSTravers(g, j);}}cout << i+1<< " ";}
}
void BFSTraverse(Graph &g)
{//從第一個節點往下,一層一層遍歷,從左往右//一個節點遍歷之后,立刻輸出置為已訪問//剩下的節點再遍歷到之前的節點時就已訪問,然后不影響操作路徑int a[MAX_VERTICES] = { 0 };//數組模擬隊列int countA = 0; int count = 0;int flag = 0;for (int i=a[count]; countA < g.numVertices-1;i=a[count] )//countA代表循環次數{for (int j = 0; j < g.numVertices; j++){if (g.matrix[a[count]][j] >0){for (int k = 0; k < g.numVertices; k++){if (a[k] == j){flag = 1;//代表之前已出現過這個點flag = 2;break;}}if (flag == 0){a[++countA] = j;}if (flag == 2)flag = 0;}}count++;}for (int i = 0; i < g.numVertices; i++)cout << a[i] +1<< " ";}void primMST(Graph* graph) {int selected[MAX_VERTICES];int parent[MAX_VERTICES];int minWeight[MAX_VERTICES];int totalWeight = 0;for (int i = 0; i < graph->numVertices; i++) {selected[i] = 0;parent[i] = -1;minWeight[i] = INT_MAX;}minWeight[0] = 1;for (int count = 0; count < graph->numVertices - 1; count++) {int minIndex = -1;int min = INT_MAX;for (int i = 0; i < graph->numVertices; i++) {if (!selected[i] && minWeight[i] < min) {min = minWeight[i];minIndex = i;}}selected[minIndex] = 1;totalWeight += min;for (int i = 0; i < graph->numVertices; i++) {if (graph->matrix[minIndex][i] && !selected[i] && graph->matrix[minIndex][i] < minWeight[i]) {parent[i] = minIndex;minWeight[i] = graph->matrix[minIndex][i];}}}printf("\n最小生成樹邊緣:\n");for (int i = 1; i < graph->numVertices; i++) {printf("%d - %d\n", parent[i]+1, i+1);}printf("總重量: %d\n", totalWeight);
}int main()
{Graph g;int n;cout << "請輸入圖中的頂點個數" << endl;cin >> n;g.numVertices = n;initialMatrix(&g,n);cout << "請輸入邊的條數和組成邊的頂點" << endl;int numEdges;cin >> numEdges;InputEdge(&g,numEdges);OutputMatrix(g, n);cout << "深度優先搜索遍歷的結果為:" << endl;DFSTravers(g, 0);cout << "\n廣度優先搜索遍歷的結果為:" << endl;BFSTraverse(g);primMST(&g);return 0;
}

三、截圖

四 調試情況、設計技巧及體會

本次實驗涉及到了建立無向圖的鄰接矩陣表示、深度優先搜索和廣度優先搜索遍歷以及最小生成樹的操作。通過完成這些實驗內容,我積累了一些寶貴的經驗和技巧,并且也遇到了一些典型的錯誤。以下是我對實驗過程中的錯誤及修改方法的總結,以及我從本次實驗中學到的技巧和經驗。

  1. 實驗過程中出現的典型錯誤及修改方法:

(1)鄰接矩陣的初始化有誤,導致后續操作出現問題

解決方法:對鄰接矩陣的初始化進行仔細檢查,確保每個元素都被正確地初始化。

(2)錯誤:在深度優先搜索或廣度優先搜索遍歷時,循環條件或循環變量設置錯誤。

修改方法:仔細檢查循環條件和循環變量的設置,確保循環能夠正確遍歷圖的所有頂點。注意邊界條件和循環變量的更新。

(3)錯誤:最小生成樹操作中,算法實現錯誤或遺漏了某些邊的處理。

修改方法:仔細閱讀最小生成樹算法的實現邏輯,確保每一步都按照算法的要求進行操作。特別是在選擇最小權重邊和更新頂點權重時,要仔細檢查條件和操作是否正確。

2. 學到的技巧和積累的經驗。

(1)在鄰接矩陣的創建過程中,我最初沒有正確理解鄰接矩陣的特性,導致了矩陣的構建錯誤。具體來說,我在構建鄰接矩陣時,沒有正確地處理頂點之間的雙向連接關系。在修正后,我明白了在鄰接矩陣中,如果頂點i與頂點j之間存在一條邊,那么矩陣的第i行和第j列上的元素值應為1,而其他位置的元素值應為0。

(2)在進行深度優先搜索時,我首先需要理解了它的基本原理:從圖的某個起始頂點開始,沿著一條路徑一直到達最深的頂點,然后回溯到之前的節點,繼續探索下一條路徑。在這個過程中,我犯了一個錯誤,那就是在訪問了某個頂點后沒有正確地回溯。修正這個錯誤后,我明白了在進行深度優先搜索時,必須正確處理訪問和未訪問的頂點狀態,才能確保遍歷的正確性。

在實現廣度優先搜索時,我遇到的問題是如何正確地訪問每一層的頂點。修正的方法是明白在廣度優先搜索中,需要使用一個隊列來存儲每一層的頂點,并且需要正確處理隊列的入隊和出隊操作。

(3)在進行Prim算法實驗時,我遇到的主要問題是如何正確地找到最小邊以及如何正確地將新頂點加入生成樹中。修正的方法是理解并實現了一個優先隊列來存儲邊,并按照邊的權重進行排序。同時,我也學會了如何正確地更新生成樹中的頂點和邊。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/210891.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/210891.shtml
英文地址,請注明出處:http://en.pswp.cn/news/210891.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

模電·放大電路的分析方法——圖解法

放大電路的分析方法——圖解法 靜態工作點的分析電壓放大倍數的分析波形非線性失真的分析直流負載線與交流負載線圖解法的適用范圍 在實際測出放大管的輸入特性、輸出特性和已知放大電路中其它各元件參數的情況下&#xff0c;利用作圖的方法對放大電路進行分析即為圖解法。 靜…

postgresql自帶指令命令系列三

目錄 簡介 bin目錄 28.pg_verifybackup 29.pg_waldump 30.postgres 31.postmaster -> postgres 32.psql 33.reindexdb 34.vacuumdb 35.vacuumlo 總結&#xff1a; 簡介 在安裝postgresql數據庫的時候會需要設置一個關于postgresql數據庫的PATH變量 export PATH/…

笙默考試管理系統-MyExamTest----codemirror(51)

笙默考試管理系統-MyExamTest----codemirror&#xff08;51&#xff09; 目錄 笙默考試管理系統-MyExamTest----codemirror&#xff08;51&#xff09; 一、 笙默考試管理系統-MyExamTest----codemirror 二、 笙默考試管理系統-MyExamTest----codemirror 三、 笙默考試…

python模塊rsa,非對稱加密算法庫

一、簡介 RSA&#xff08;Rivest-Shamir-Adleman&#xff09;是一種非對稱加密算法&#xff0c;廣泛應用于數據加密和數字簽名等安全領域。以下是對RSA算法的介紹以及其優缺點&#xff1a; 1.密鑰生成&#xff1a;RSA算法生成一對密鑰&#xff0c;包括公鑰和私鑰。公鑰用于加密…

Linux CentOS 7.6安裝jdk1.8教程

安裝教程 第一種方式&#xff08;通過yum安裝&#xff09;&#xff1a;第一步&#xff1a;輸入查找命令&#xff1a;第二步&#xff1a;輸入安裝命令&#xff1a;第三步&#xff1a;安裝完成&#xff0c;輸入安裝命令后&#xff0c;等到出現Complete&#xff01;代表安裝完成第…

PyTorch實現邏輯回歸

最終效果 先看下最終效果&#xff1a; 這里用一條直線把二維平面上不同的點分開。 生成隨機數據 #創建訓練數據 x torch.rand(10,1)*10 #shape(10,1) y 2*x (5 torch.randn(10,1))#構建線性回歸參數 w torch.randn((1))#隨機初始化w&#xff0c;要用到自動梯度求導 b …

使用 ROS 和 Geomagic Haptic 驅動 Franka 機械臂

文章目錄 前言一、安裝 franka_ros二、安裝 OpenHaptics for Linux三、安裝 3D Systems Geomagic Touch ROS Driver四、安裝 franka_interactive_controllers五、使用 Geomagic Haptic 驅動 Franka 機械臂 前言 本文為在雙系統上使用 ROS 和 Geomagic Haptic 驅動 Franka 機械…

滑動窗口(單調隊列)

154. 滑動窗口 - AcWing題庫 給定一個大小為 n≤10^6≤10^6 的數組。 有一個大小為 k 的滑動窗口&#xff0c;它從數組的最左邊移動到最右邊。 你只能在窗口中看到 k 個數字。 每次滑動窗口向右移動一個位置。 以下是一個例子&#xff1a; 該數組為 [1 3 -1 -3 5 3 6 7]&…

HashMap的那些事

一、HashMap與HashTable的區別 1.來歷 HashTable是一種鍵值映射的數據結構&#xff0c;自從java發布就存在&#xff0c;而HashMap是jdk1.2后才出現的&#xff0c;雖然說HashTable出現得早且線程安全&#xff0c;但是效率很低已經棄用了&#xff0c;現在HashMap逐漸成為主流 …

Nmap腳本未來的發展趨勢

Nmap腳本技術的發展趨勢和前景 Nmap腳本是一種基于Lua語言開發的腳本&#xff0c;可以擴展Nmap的功能&#xff0c;用于自動化掃描、漏洞檢測、服務探測、設備管理等方面。隨著網絡安全的不斷發展和漏洞的不斷出現&#xff0c;Nmap腳本技術也在不斷發展和壯大。在本文中&#xf…

小米手機鎖屏時間設置為永不休眠_手機不息屏_保持亮屏

環境&#xff1a;打開手機自帶的鎖屏時間設置發現沒有 永不息屏的選項 原因&#xff1a;采用了三星OLED屏幕&#xff0c;所以根據OLED屏幕特性&#xff0c;這個是為了防止燒屏而特意設計的。非OLED機型支持設置“永不” 解決方案1&#xff1a;原生系統是支持永不鎖屏的&#…

Android 13 - Media框架(20)- ACodec(二)

這一節開始我們就來學習 ACodec 的實現 1、創建 ACodec ACodec 是在 MediaCodec 中創建的&#xff0c;這里先貼出創建部分的代碼&#xff1a; mCodec mGetCodecBase(name, owner);if (mCodec NULL) {ALOGE("Getting codec base with name %s (owner%s) failed", n…

ES 如何將國際標準時間格式進行格式化與調整時區

需求&#xff0c;日志收集的時候&#xff0c;時間格式是國際標準時間格式。形如yyyy-MM-ddTHH:mm:ss.SSS。 &#xff08;2023-12-05T02:45:50.282Z&#xff09;這個時區也不對&#xff0c;那如何將此類型的時間&#xff0c;進行格式化呢&#xff1f; 本篇文章體統一個案例&…

Other -- ChatGPT 原理

本文為個人理解&#xff0c;幫助小白&#xff08;本人就是&#xff09;了解正在創建新時代的 AI 產品&#xff0c;如文中理解有誤歡迎留言。 [參考鏈接--](https://baijiahao.baidu.com/s?id1765556782543603120&wfrspider&forpc) 1. 了解一些基本概念 大語言模型&a…

修改 Ganglia 監控 Grid Report timezone 時區 為 東八區 +8 PRC

Ganglia 監控 Grid Report timezone 默認時區 為 零時區 0 現在要修改為 東八區 8 具體操作如下 modify ganglia-web report timezone 0 --> 8 vim /apps/svr/httpd-2.4.48/htdocs/ganglia/header.php // add timezone GMT8 ini_set(date.timezone, PRC);詳細記錄&#x…

【面試】測試/測開(ING)

63. APP端特有的測試 參考&#xff1a;APP專項測試、APP應用測試 crash和anr的區別 1&#xff09;網絡測試 2&#xff09;中斷測試 3&#xff09;安裝、卸載測試 4&#xff09;兼容測試 5&#xff09;性能測試&#xff08;耗電量、流量、內存、服務器端&#xff09; 6&#xf…

畫對比折線圖【Python】

出這一期想必是我做某個課程作業遇到了。 由于去各個官網下載對比圖要錢&#xff0c;我還是不想花錢的&#xff01;真討厭&#xff01;淺淺水一期。 以下是要做的對比圖的數據&#xff1a; 代碼&#xff1a; from matplotlib import pyplot as plt#設置中文顯示plt.rcParams[…

CSS新手入門筆記整理:CSS浮動布局

文檔流概述 正常文檔流 “文檔流”指元素在頁面中出現的先后順序。正常文檔流&#xff0c;又稱為“普通文檔流”或“普通流”&#xff0c;也就是W3C標準所說的“normal flow”。正常文檔流&#xff0c;將一個頁面從上到下分為一行一行&#xff0c;其中塊元素獨占一行&#xf…

ChatGPT OpenAI API請求限制 嘗試解決

1. OpenAI API請求限制 Retrying langchain.chat_models.openai.ChatOpenAI.completion_with_retry.._completion_with_retry in 4.0 seconds as it raised RateLimitError: Rate limit reached for gpt-3.5-turbo-16k in organization org-U7I2eKpAo6xA7RUa2Nq307ae on reques…

讓內存無處可逃:智能指針[C++11]

智能指針 文章目錄 智能指針前言RAII什么是智能指針智能指針的應用示例 C98的auto_ptr共享型智能指針&#xff1a;shared_ptrshared_ptr的使用初始化獲取原生指針指定刪除器默認刪除器default_delete指定刪除器指定刪除器管理動態數組 shared_ptr的偽實現shared_ptr的注意事項避…