數據結構之普利姆算法

前言:Prim算法是圖論中的算法,用來生成圖的最小生成樹。本篇文章介紹算法的流程,實現思想,和具體代碼實現,使用c語言。學習需要輸出才能理解的更透徹,所以說堅持寫文章,希望可以用自己的方式把一些知識的原理描述出來。我會結合示意圖清晰地展現出所有的流程,用人類語言把整個過程表述清楚,在寫代碼的時候才能做到胸有成竹,而不是模棱兩可或者說差不多就是這樣。本篇文章假設你已經具有了基本的數據結構和c語言的基礎。
分享一個學習算法的神奇網站,可以可視化算法的執行過程。
Prim算法

一、Prim算法實現思路

Prim算法的作用是實現圖的最小生成樹。
在這里插入圖片描述

Prim算法使用的是貪心算法的策略,每次都會找和當前的節點相連的邊中,權值最小的節點。以上面這個圖為例,首先我們要確定最小生成樹的根節點,我們就設定為0節點。下面我們分步驟進行
① 根據貪心算法的原則,與0相連的下一個節點,我們要找0節點的邊中,權值最小的邊,0節點相連的一共有4條邊,分別是

起點終點權值
015
021
035
047

找到權值最小的,就是連接2號節點的邊,權值為1,所以會將2號節點加入到最小生成樹中。
在這里插入圖片描述
② 現在構成了圖中所畫的一棵生成樹,需要將這兩個節點看成一個整體,找和這棵生成樹相連的邊中,權值最小的邊,所有的邊:

起點終點權值
015
035
047
248
252
268

最小的邊就是連接2號節點和五號節點的邊,權值為2,然后就將5號節點加入到生成樹中,并且5號節點連的是2號節點,就會生成下面這棵生成樹
在這里插入圖片描述

③接下來看和 1-2-5 生成樹相連的節點的權值,所有的邊:

起點終點權值
015
035
047
248
268
573
534

權值最小的邊就是連接5號節點和3號節點的邊,權值為3,那么就將3號節點加入到生成樹中,生成樹如下:
在這里插入圖片描述
④ 再看和當前的生成樹相連的所有邊:

起點終點權值
015
035
047
248
268
534
748

權值最小的邊是連接5號節點和3號節點的邊,權值為4,構成的生成樹如下:
在這里插入圖片描述
⑤ 這里有一個需要注意的地方,就是最小生成樹一定是不能有環,所以從3到0的邊就不能再考慮了,和當前生成樹相連的邊:

起點終點權值
015
047
248
268
748
314

權值最小的邊是連接3號節點和1號節點的邊,權值為4,那么就將1號節點加入到生成樹:
在這里插入圖片描述
⑥ 去除會形成回路的邊 0 -> 5, 和當前的生成樹相連的所有的邊:

起點終點權值
047
248
268
748
其中權值最小的邊是 連接0號節點和4號節點的邊,權值為7,將4號節點加入生成樹,形成下面一個生成樹:

在這里插入圖片描述
⑦ 此時的邊只有兩條了,因為形成回路的邊要去掉

起點終點權值
268
467
選擇連接4號節點和6號節點的邊,權值為7,至此所有的節點添加完畢

在這里插入圖片描述

二、代碼實現

通過上面的文字描述和圖像展示,我們已經了解到了普利姆算法的執行的流程,接下來我們看一下代碼層面的實現。分析一個問題,首先是站在人類思維像上面一樣,寫出步驟,然后就是需要轉化成代碼。這個過程還是挺復雜的,比較抽象。
一個功能的代碼實現大概可以分為下面:
1、數據的類型、常量,需要定義結構體和常量,常量如最大值的限定等
2、入參
3、主函數
4、初始化輔助變量,需要分析都需要什么輔助的變量
5、流程執行
7、輸出結果,printf或者return
當然關鍵就是第五步,其實前置的步驟都是為第五步服務的。我們先分析一下主流程需要做什么:
1、找和當前生成樹相連的邊中權值最小的邊
2、將邊加入當前生成樹
3、需要記錄當前的節點相連的在生成樹中的節點,才能正確繪制樹
那么我們就需要一個數組,來存儲和當前生成樹直接相連的所有的邊的權值,其實就是節點到生成樹的距離,如果節點在生成樹內部,那么距離就是0,如果沒有直接相連,那么距離就是正無窮,這個數組的名字取做 lowcost,意為最低成本的構成樹,這個數組的初始化需要通過遍歷鄰接數組獲取,我們都假設樹的根節點為0號節點,那么lowcost 初始時就是0號節點到所有其他節點的距離,就是鄰接數組的第一行。
需要一個數組來記錄當前的節點相連的在生成樹中的節點,記為 adjvex 數組,意為臨近節點,初始化都為 0,
這兩個數組通過下標來和節點一一對應。
然后我們需要比較生成樹的邊中,權值最小的邊,也就是需要一個min變量,遍歷所有的邊,不斷更新min,讓它變成最小的權值,并且如果一個節點離生成樹的距離最小,我們還要記錄這個節點,記為 k。
k 節點需要加入到生成樹中,也就是將 k 節點放在生成樹中,也就是 k 節點對應的 lowcost[k] 要置為0,表示k節點到生成樹的距離為0,權值和距離其實是一個意思。
將 k 節點加入到生成樹中之后,還需要更新 adjvex 數組,想象一下,如果之前 0 -> 3 節點 沒有路徑,初始時 lowcost[3] = 正無窮,但是 0 -> 2 有路徑,并且 2 -> 3 有路徑,此時就需要更新 3 節點相連的節點,也就是 adjvex[3] 修改成 2,lowcost[3] = 2到3的距離,但是如果后面4號節點加入樹,并且 4-> 3 的路徑更短了,那就需要修改 adjvex[3] = 4lowcost[3] = 4到3的距離。所以說需要對比從 k 到 j 的距離和當前的 lowcost[j],如果k 到 j 的距離更小,需要更新lowcost[j] = k到j的距離adjvex[j] = k
上面流程走完之后,是實現了第一個權值最小的邊的節點加入到生成樹,所以整體需要循環n次,n為樹的節點數
接下來根據主流程分析一下需要初始化的數據:
1、需要兩層循環,i、j 作為循環變量
2、需要一個 min 值,初始化為一個c語言中的最大值
3、k 記錄權值最小的邊對應的節點
4、lowcost 數組,記錄權值
5、adjvex 數組,記錄鄰近節點
需要定義的數據結構和常量:
1、圖的結構體
2、MAXVEX 表示最大節點數
入參就是 圖
接下來看實際的代碼吧,相信通過上面的分析你已經非常清楚每句代碼的作用

// 普利姆算法
#include <stdio.h>
#include <limits.h>#define MAXVEX 100  // 最大頂點數// 圖的鄰接矩陣表示
typedef struct {int vexnum;  // 頂點數int arcnum;  // 邊數int arcs[MAXVEX][MAXVEX];  // 鄰接矩陣
} MGraph;void MiniSpanTree_Prim(MGraph G){int min,i,j,k;int adjvex[MAXVEX]; // 保存鄰接頂點下標的數組int lowcost[MAXVEX]; // 記錄當前生成樹到剩余頂點的最小權值lowcost[0] = 0; // 初始化第一個權值為0,即v0加入生成樹adjvex[0] = 0; // 將0號頂點作為第一個頂點加入到樹中for(i=1;i<G.vexnum;i++){ // 除了下標為0以外的所有頂點lowcost[i] = G.arcs[0][i]; // 將與下標為0的頂點有邊的權值存入lowcost數組adjvex[i] = 0; // 這些頂點的adjvex數組元素都為0}// 算法核心for(i=1;i<G.vexnum;i++){  // 只需要循環vexnum-1次min = INT_MAX;  // 使用更合適的最大值j=0;k=0;// 找出lowcost中最小值,最小權值給min,最小值的下標給kfor(j=1;j<G.vexnum;j++){  // 從1號頂點開始找if(lowcost[j]!=0 && lowcost[j]<min){ // 不在生成樹中的頂點而且權值更小的min = lowcost[j];  // 更新更小的值k = j;  // 找q到了新的點下標給k}}printf("邊(%d,%d) 權值:%d\n",adjvex[k],k,min);  // 打印權值最小的邊lowcost[k] = 0; // 將這個頂點加入生成樹for(j=1;j<G.vexnum;j++){if(lowcost[j]!=0 && G.arcs[k][j]<lowcost[j]){ // 如果新加入的頂點k使權值更小lowcost[j] = G.arcs[k][j];  // 更新更小的權值adjvex[j] = k;  //修改這條邊鄰接的頂點}}}
}// 初始化測試圖
void initTestGraph(MGraph *G) {int i, j;// 初始化鄰接矩陣為無窮大(用大數值表示)for(i = 0; i < MAXVEX; i++) {for(j = 0; j < MAXVEX; j++) {if(i == j) {G->arcs[i][j] = 0;  // 自己到自己距離為0} else {G->arcs[i][j] = INT_MAX;  // 無邊用最大值表示}}}// 設置頂點數G->vexnum = 6;  // 0-5共6個頂點// 添加邊(無向圖,需要設置兩個方向)// 邊 0-1,權值4G->arcs[0][1] = G->arcs[1][0] = 4;// 邊 0-2,權值6  G->arcs[0][2] = G->arcs[2][0] = 6;// 邊 0-3,權值16G->arcs[0][3] = G->arcs[3][0] = 16;// 邊 1-2,權值10G->arcs[1][2] = G->arcs[2][1] = 10;// 邊 1-4,權值7G->arcs[1][4] = G->arcs[4][1] = 7;// 邊 2-3,權值14G->arcs[2][3] = G->arcs[3][2] = 14;// 邊 2-4,權值3G->arcs[2][4] = G->arcs[4][2] = 3;// 邊 2-5,權值8G->arcs[2][5] = G->arcs[5][2] = 8;// 邊 4-5,權值9G->arcs[4][5] = G->arcs[5][4] = 9;
}int main() {MGraph G;printf("=== 普里姆最小生成樹算法演示 ===\n\n");// 初始化測試圖initTestGraph(&G);printf("圖的頂點數:%d\n", G.vexnum);printf("圖的邊信息:\n");printf("0-1: 4, 0-2: 6, 0-3: 16\n");printf("1-2: 10, 1-4: 7\n");printf("2-3: 14, 2-4: 3, 2-5: 8\n");printf("4-5: 9\n\n");printf("開始執行普里姆算法:\n");printf("最小生成樹的邊:\n");// 執行普里姆算法MiniSpanTree_Prim(G);printf("\n================================\n");printf("算法執行完成!\n");printf("實際結果:總權值 = 4+6+3+8+14 = 35\n");return 0;
}

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

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

相關文章

構建強大的物聯網架構所需了解的一切

數據正驅動著當今的商業發展&#xff0c;而物聯網&#xff08;IoT&#xff09;則有助于為企業的增長和創新開辟新的機遇。麥肯錫的研究表明&#xff0c;全球數據在四年內實現了驚人的 7 倍增長。隨著越來越多的物聯網設備進入市場&#xff0c;更多企業開始需要強大的物聯網架構…

java之json轉excel生成

背景 業務為實現自定義樣式excel的導出&#xff0c;常規的做法就是根據數據在代碼中進行類似模版的配置&#xff1b;這樣的體驗不是很好&#xff0c;只要用戶改變下樣式的設置不用代碼改動就能實現自定義excel的導出更加靈活。 以下是具體實現 pom依賴 <dependency><g…

新版本Cursor中配置自定義MCP服務器教程,附MCP工具開發實戰源碼

在 Cursor 中配置自定義 MCP 服務器&#xff1a;打造你的 AI 開發工具鏈 引言 隨著 AI 編程助手的普及&#xff0c;開發者們越來越希望能夠定制化自己的開發環境。Cursor 作為一款強大的 AI 編程編輯器&#xff0c;提供了 Model Context Protocol (MCP) 支持&#xff0c;新版本…

前端面試十二之vue3基礎

一、ref和reactive在 Vue 3 中&#xff0c;ref 和 reactive 是兩種主要的響應式數據創建方式&#xff0c;它們各有特點和適用場景。1.refref 主要用于創建單個值的響應式引用&#xff0c;通常用于基本類型數據&#xff0c;如數字、字符串等。使用 ref 創建的引用對象可以通過 .…

設計模式四:裝飾模式(Decorator Pattern)

裝飾模式是一種結構型設計模式&#xff0c;它允許你動態地給一個對象添加額外的職責&#xff0c;相比繼承更加靈活。1. 模式定義裝飾模式&#xff1a;動態地給一個對象添加一些額外的職責。就增加功能來說&#xff0c;裝飾模式相比生成子類更為靈活。2. 模式結構主要角色&#…

神經網絡常見激活函數 14-Mish函數

文章目錄Mish函數導函數函數和導函數圖像優缺點PyTorch 中的 Mish 函數TensorFlow 中的 Mish 函數Mish 論文 https://arxiv.org/pdf/1908.08681 函數導函數 Mish函數 Mish(x)x?tanh??(softplus(x))x?tanh??(ln??(1ex))\begin{aligned} \text{Mish}(x) & x \cdot \t…

LAMP遷移LNMP Nginx多站點配置全流程

文章目錄前言備份與停止服務nginx安裝與配置nginx 編譯安裝配置服務php-fpm多站點配置phf-fpm介紹多站點配置nginx 多站點配置nginx ssl 配置參考前言 之前服務器使用的是 LAMP環境&#xff0c;想充分利用服務器資源&#xff0c;再運行另外一個站點 在LAMP環境下應該是也可以…

Nginx屏蔽國外IP訪問

下載IP列表 # 下載到文件 wget http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest # 直接輸出到終端 curl -sSL https://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest得到一份國內IP配置 # 原始IP列表格式&#xff1a;apnic|CN|ipv4|218.78.0.0|1310…

stl-string模擬

1.介紹主要進行cpp中string的模擬&#xff0c;方便我們更好的對stl進行使用&#xff0c;string沒有模板&#xff0c;我們將頭文件和函數寫在兩個不同的文件2.頭文件3.cpp文件如有問題&#xff0c;歡迎糾正&#xff01;

基于MATLAB的極限學習機ELM的數據回歸預測方法應用

說明&#xff1a;這是一個機器學習實戰項目&#xff08;附帶數據代碼文檔&#xff09;&#xff0c;如需數據代碼文檔可以直接到文章最后關注獲取 或者私信獲取。 1.項目背景 在當今的數據驅動時代&#xff0c;準確且高效的預測模型對于解決復雜問題至關重要。極限學習機&#…

芯谷科技--雙四通道模擬/數字多路復用器74HC4052

在電子系統中&#xff0c;信號的多路復用與解復用是常見的需求&#xff0c;特別是在需要對多個信號源進行選擇和切換的場景中。芯谷科技推出的 74HC4052 雙四通道模擬/數字多路復用器/解復用器&#xff0c;以其高效、靈活的設計&#xff0c;為工程師提供了可靠的解決方案。產品…

基于MATLAB的極限學習機ELM的數據分類預測方法應用

說明&#xff1a;這是一個機器學習實戰項目&#xff08;附帶數據代碼文檔&#xff09;&#xff0c;如需數據代碼文檔可以直接到文章最后關注獲取 或者私信獲取。 1.項目背景 在現代數據挖掘與機器學習領域&#xff0c;面對日益復雜的數據結構和快速增長的數據量&#xff0c;開…

復合機器人在生物制藥實驗室上下料搬運案例

在醫療行業的物料搬運環節&#xff0c;傳統的人工操作模式逐漸暴露出諸多弊端&#xff0c;成為制約企業發展的瓶頸。富唯智能通過引入先進的復合機器人技術&#xff0c;為醫療企業提供了高效、智能的上下料搬運解決方案&#xff0c;助力醫療行業實現自動化與智能化升級。?客戶…

嵌入式學習-PyTorch(7)-day23

損失函數的調用import torch from torch import nn from torch.nn import L1Lossinputs torch.tensor([1.0,2.0,3.0]) target torch.tensor([1.0,2.0,5.0])inputs torch.reshape(inputs, (1, 1, 1, 3)) target torch.reshape(target, (1, 1, 1, 3)) #損失函數 loss L1Loss…

用 Ray 跨節點調用 GPU 部署 DeepSeek 大模型,實現分布式高效推理

在大模型時代&#xff0c;單節點 GPU 資源往往難以滿足大模型&#xff08;如 7B/13B 參數模型&#xff09;的部署需求。借助 Ray 分布式框架&#xff0c;我們可以輕松實現跨節點 GPU 資源調度&#xff0c;讓大模型在多節點間高效運行。本文將以 DeepSeek-llm-7B-Chat 模型為例&…

快速了解 HTTPS

1. 引入 在 HTTP 協議 章節的 reference 段&#xff0c;曾提到過 HTTPS。這里對HTTPS進行詳細介紹。 HTTPS 是在 HTTP 的基礎上&#xff0c;引入了一個加密層 (SSL)。HTTP 是明文傳輸的 (不安全)。當下所見到的大部分網站都是 HTTPS 的。 起初是拜運營商劫持所賜&#xff08;…

mysql備份與視圖

要求:1.將mydb9_stusys數據庫下的student、sc 和course表&#xff0c;備份到本地主機保存為st_msg_bak.sql文件&#xff0c;然后將數據表恢復到自建的db_test數據庫中&#xff1b;2.在db_test數據庫創建一視圖 stu_info,查詢全體學生的姓名&#xff0c;性別&#xff0c;課程名&…

【數據結構】 鏈表 + 手動實現單鏈表和雙鏈表的接口(圖文并茂附完整源碼)

文章目錄 一、 鏈表的概念及結構 二、鏈表的分類 ?編輯 三、手動實現單鏈表 1、定義單鏈表的一個節點 2、打印單鏈表 3、創建新節點 4、單鏈表的尾插 5、單鏈表的頭插 6、單鏈表的尾刪 7、單鏈表的頭刪 8、單鏈表的查找 9、在指定位置之前插入一個新節點 10、在指…

Go語言時間控制:定時器技術詳細指南

1. 定時器基礎&#xff1a;從 time.Sleep 到 time.Timer 的進化為什么 time.Sleep 不夠好&#xff1f;在 Go 編程中&#xff0c;很多人初學時會用 time.Sleep 來實現時間控制。比如&#xff0c;想讓程序暫停 2 秒&#xff0c;代碼可能是這樣&#xff1a;package mainimport (&q…

C# 轉換(顯式轉換和強制轉換)

顯式轉換和強制轉換 如果要把短類型轉換為長類型&#xff0c;讓長類型保存短類型的所有位很簡單。然而&#xff0c;在其他情況下&#xff0c; 目標類型也許無法在不損失數據的情況下容納源值。 例如&#xff0c;假設我們希望把ushort值轉化為byte。 ushort可以保存任何0~65535的…