基于C#實現Prim算法

圖論在數據結構中是非常有趣而復雜的,作為 Web 碼農的我,在實際開發中一直沒有找到它的使用場景,不像樹那樣的頻繁使用,不過還是準備仔細的把圖論全部過一遍。

一、最小生成樹

圖中有一個好玩的東西叫做生成樹,就是用邊來把所有的頂點聯通起來,前提條件是最后形成的聯通圖中不能存在回路,所以就形成這樣一個推理:假設圖中的頂點有 n 個,則生成樹的邊有 n-1 條,多一條會存在回路,少一路則不能把所有頂點聯通起來,如果非要在圖中加上權重,則生成樹中權重最小的叫做最小生成樹。
image.png
對于上面這個帶權無向圖來說,它的生成樹有多個,同樣最小生成樹也有多個,因為我們比的是權重的大小。

二、Prim 算法

求最小生成樹的算法有很多,常用的是 Prim 算法和 Kruskal 算法,為了保證單一職責,我把 Kruskal 算法放到下一篇,那么 Prim 算法的思想是什么呢?很簡單,貪心思想。
如上圖:現有集合 M={A,B,C,D,E,F},再設集合 N={}。

  • 第一步:挑選任意節點(比如 A),將其加入到 N 集合,同時剔除 M 集合的 A。
  • 第二步:尋找 A 節點權值最小的鄰節點(比如 F),然后將 F 加入到 N 集合,此時 N={A,F},同時剔除 M 集合中的 F。
  • 第三步:尋找{A,F}中的權值最小的鄰節點(比如 E),然后將 E 加入到 N 集合,此時 N={A,F,E},同時剔除 M 集合的 E。
  • 。。。

最后 M 集合為{}時,生成樹就構建完畢了,是不是非常的簡單,這種貪心做法我想大家都能想得到,如果算法配合一個好的數據結構,就會如虎添翼。

三、代碼

1、圖的存儲

圖的存儲有很多方式,鄰接矩陣,鄰接表,十字鏈表等等,當然都有自己的適合場景,下面用鄰接矩陣來玩玩,鄰接矩陣需要采用兩個數組,
①. 保存頂點信息的一維數組,
②. 保存邊信息的二維數組。

 public class Graph{/// <summary>/// 頂點個數/// </summary>public char[] vertexs;/// <summary>/// 邊的條數/// </summary>public int[,] edges;/// <summary>/// 頂點個數/// </summary>public int vertexsNum;/// <summary>/// 邊的個數/// </summary>public int edgesNum;}

2、矩陣構建

矩陣構建很簡單,這里把上圖中的頂點和權的信息保存在矩陣中。

 #region 矩陣的構建/// <summary>/// 矩陣的構建/// </summary>public void Build(){//頂點數graph.vertexsNum = 6;//邊數graph.edgesNum = 8;graph.vertexs = new char[graph.vertexsNum];graph.edges = new int[graph.vertexsNum, graph.vertexsNum];//構建二維數組for (int i = 0; i < graph.vertexsNum; i++){//頂點graph.vertexs[i] = (char)(i + 65);for (int j = 0; j < graph.vertexsNum; j++){graph.edges[i, j] = int.MaxValue;}}graph.edges[0, 1] = graph.edges[1, 0] = 80;graph.edges[0, 3] = graph.edges[3, 0] = 100;graph.edges[0, 5] = graph.edges[5, 0] = 20;graph.edges[1, 2] = graph.edges[2, 1] = 90;graph.edges[2, 5] = graph.edges[5, 2] = 70;graph.edges[3, 2] = graph.edges[2, 3] = 100;graph.edges[4, 5] = graph.edges[5, 4] = 40;graph.edges[3, 4] = graph.edges[4, 3] = 60;graph.edges[2, 3] = graph.edges[3, 2] = 10;}#endregion

3、Prim

要玩 Prim,我們需要兩個字典。
①:保存當前節點的字典,其中包含該節點的起始邊和終邊以及權值,用 weight=-1 來記錄當前節點已經訪問過,用 weight=int.MaxValue 表示兩節點沒有邊。
②:輸出節點的字典,存放的就是我們的 N 集合。
當然這個復雜度玩高了,為 O(N2),尋找 N 集合的鄰邊最小權值時,我們可以玩玩 AVL 或者優先隊列來降低復雜度。

 #region prim算法/// <summary>/// prim算法/// </summary>public Dictionary<char, Edge> Prim(){Dictionary<char, Edge> dic = new Dictionary<char, Edge>();//統計結果Dictionary<char, Edge> outputDic = new Dictionary<char, Edge>();//weight=MaxValue:標識沒有邊for (int i = 0; i < graph.vertexsNum; i++){//起始邊var startEdge = (char)(i + 65);dic.Add(startEdge, new Edge() { weight = int.MaxValue });}//取字符的開始位置var index = 65;//取當前要使用的字符var start = (char)(index);for (int i = 0; i < graph.vertexsNum; i++){//標記開始邊已使用過dic[start].weight = -1;for (int j = 1; j < graph.vertexsNum; j++){//獲取當前 c 的 鄰邊var end = (char)(j + index);//取當前字符的權重var weight = graph.edges[(int)(start) - index, j];if (weight < dic[end].weight){dic[end] = new Edge(){weight = weight,startEdge = start,endEdge = end};}}var min = int.MaxValue;char minkey = ' ';foreach (var key in dic.Keys){//取當前 最小的 key(使用過的除外)if (min > dic[key].weight && dic[key].weight != -1){min = dic[key].weight;minkey = key;}}start = minkey;//邊為頂點減去1if (outputDic.Count < graph.vertexsNum - 1 && !outputDic.ContainsKey(minkey)){outputDic.Add(minkey, new Edge(){weight = dic[minkey].weight,startEdge = dic[minkey].startEdge,endEdge = dic[minkey].endEdge});}}return outputDic;}#endregion

4、最后我們來測試一下,看看找出的最小生成樹。

 public static void Main(){MatrixGraph martix = new MatrixGraph();martix.Build();var dic = martix.Prim();Console.WriteLine("最小生成樹為:");foreach (var key in dic.Keys){Console.WriteLine("({0},{1})({2})", dic[key].startEdge, dic[key].endEdge, dic[key].weight);}Console.Read();}

image.png

 using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Diagnostics;using System.Threading;using System.IO;using SupportCenter.Test.ServiceReference2;using System.Threading.Tasks;namespace ConsoleApplication2{public class Program{public static void Main(){MatrixGraph martix = new MatrixGraph();martix.Build();var dic = martix.Prim();Console.WriteLine("最小生成樹為:");foreach (var key in dic.Keys){Console.WriteLine("({0},{1})({2})", dic[key].startEdge, dic[key].endEdge, dic[key].weight);}Console.Read();}}/// <summary>/// 定義矩陣節點/// </summary>public class MatrixGraph{Graph graph = new Graph();public class Graph{/// <summary>/// 頂點個數/// </summary>public char[] vertexs;/// <summary>/// 邊的條數/// </summary>public int[,] edges;/// <summary>/// 頂點個數/// </summary>public int vertexsNum;/// <summary>/// 邊的個數/// </summary>public int edgesNum;}#region 矩陣的構建/// <summary>/// 矩陣的構建/// </summary>public void Build(){//頂點數graph.vertexsNum = 6;//邊數graph.edgesNum = 8;graph.vertexs = new char[graph.vertexsNum];graph.edges = new int[graph.vertexsNum, graph.vertexsNum];//構建二維數組for (int i = 0; i < graph.vertexsNum; i++){//頂點graph.vertexs[i] = (char)(i + 65);for (int j = 0; j < graph.vertexsNum; j++){graph.edges[i, j] = int.MaxValue;}}graph.edges[0, 1] = graph.edges[1, 0] = 80;graph.edges[0, 3] = graph.edges[3, 0] = 100;graph.edges[0, 5] = graph.edges[5, 0] = 20;graph.edges[1, 2] = graph.edges[2, 1] = 90;graph.edges[2, 5] = graph.edges[5, 2] = 70;graph.edges[3, 2] = graph.edges[2, 3] = 100;graph.edges[4, 5] = graph.edges[5, 4] = 40;graph.edges[3, 4] = graph.edges[4, 3] = 60;graph.edges[2, 3] = graph.edges[3, 2] = 10;}#endregion#region 邊的信息/// <summary>/// 邊的信息/// </summary>public class Edge{//開始邊public char startEdge;//結束邊public char endEdge;//權重public int weight;}#endregion#region prim算法/// <summary>/// prim算法/// </summary>public Dictionary<char, Edge> Prim(){Dictionary<char, Edge> dic = new Dictionary<char, Edge>();//統計結果Dictionary<char, Edge> outputDic = new Dictionary<char, Edge>();//weight=MaxValue:標識沒有邊for (int i = 0; i < graph.vertexsNum; i++){//起始邊var startEdge = (char)(i + 65);dic.Add(startEdge, new Edge() { weight = int.MaxValue });}//取字符的開始位置var index = 65;//取當前要使用的字符var start = (char)(index);for (int i = 0; i < graph.vertexsNum; i++){//標記開始邊已使用過dic[start].weight = -1;for (int j = 1; j < graph.vertexsNum; j++){//獲取當前 c 的 鄰邊var end = (char)(j + index);//取當前字符的權重var weight = graph.edges[(int)(start) - index, j];if (weight < dic[end].weight){dic[end] = new Edge(){weight = weight,startEdge = start,endEdge = end};}}var min = int.MaxValue;char minkey = ' ';foreach (var key in dic.Keys){//取當前 最小的 key(使用過的除外)if (min > dic[key].weight && dic[key].weight != -1){min = dic[key].weight;minkey = key;}}start = minkey;//邊為頂點減去1if (outputDic.Count < graph.vertexsNum - 1 && !outputDic.ContainsKey(minkey)){outputDic.Add(minkey, new Edge(){weight = dic[minkey].weight,startEdge = dic[minkey].startEdge,endEdge = dic[minkey].endEdge});}}return outputDic;}#endregion}}

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

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

相關文章

前端項目搭建Webpack的配置

本人這次是在搭建一個Typescript項目時候配置的Webpack。但是Typescript的項目本人看來和往常的Web(Vue)項目類似點很多的。那么我們就可以通過對該Typescript項目的略微調整即可挪到Web項目中....... 首先說明一下為什么要依賴WebPack來搭建項目&#xff1f;&#xff1f;&…

ES 萬條以外分頁檢索功能實現及注意事項

背景 以 ES 存儲日志&#xff0c;且需要對日志進行分頁檢索&#xff0c;當數據量過大時&#xff0c;就面臨 ES 萬條以外的數據檢索問題&#xff0c;如何利用滾動檢索實現這個需求呢&#xff1f;本文介紹 ES 分頁檢索萬條以外的數據實現方法及注意事項。 需求分析 用 ES 存儲數…

Redis 反序列化失敗

文章目錄 問題原序列化配置修改配置解決方法 問題 com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of org.springframework.security.core.authority.SimpleGrantedAuthority (although at least one Creator exists): cannot deser…

css圖片縮放屬性object-fit說明

object-fit 屬性可以設置以下值&#xff1a; 屬性值說明例子fill填充容器&#xff0c;可能會改變圖片的比例。object-fit: fill;contain保持圖片的原始比例&#xff0c;確保圖片完全包含在容器內。object-fit: contain;cover保持圖片的原始比例&#xff0c;確保圖片覆蓋整個容…

性能優化中使用Profiler進行頁面卡頓的排查及解決方式

文章目錄 一、前言二、頁面卡頓的排查方式1、耗時操作的監控2、頁面卡頓的監控 三、參考鏈接 一、前言 程序的優化在做過線上bug處理&#xff0c;布局層級優化&#xff0c;項目依賴庫版本更新&#xff0c;重復庫合并&#xff0c;刪除未使用的資源&#xff0c;刪除冗余的庫&…

機器學習【01】相關環境的安裝

學習實例 參考資料&#xff1a;聯邦學習實戰{楊強}https://book.douban.com/subject/35436587/ 項目地址&#xff1a;https://github.com/FederatedAI/Practicing-Federated-Learning/tree/main/chapter03_Python_image_classification 一、環境準備 GPU安裝CUDA、cuDNN pytho…

ComboGrid中快捷鍵Enter使用

為了實現當前元素&#xff0c;回車時有值跳轉到下一個元素&#xff0c;無值則查詢。 定義元素時使用快捷鍵 $.fn.combogrid.defaults.keyHandler.up.call(this);調用combogrid默認的快捷鍵 $(#cs).combogrid({width: 360,placeholder: 測試...,panelWidth: 1000,qParams: {pJ…

letcode::數組中的第k個最大元素

數組中的第k個最大元素 給定整數數組 nums 和整數 k&#xff0c;請返回數組中第 k 個最大的元素。 請注意&#xff0c;你需要找的是數組排序后的第 k 個最大的元素&#xff0c;而不是第 k 個不同的元素。 你必須設計并實現時間復雜度為 O(n) 的算法解決此問題。 示例 1: 輸入: …

PHP 語法||PHP 變量

PHP 腳本在服務器上執行&#xff0c;然后將純 HTML 結果發送回瀏覽器。 基本的 PHP 語法 PHP 腳本可以放在文檔中的任何位置。 PHP 腳本以 <?php 開始&#xff0c;以 ?> 結束&#xff1a; <?php // PHP 代碼 ?> 值得一提的是&#xff0c;通過設定php.ini的相…

nvm-切換node版本工具安裝-方便好用

去官網下載&#xff1a; https://github.com/coreybutler/nvm-windows#installation--upgrades 網站進去后點擊下載&#xff0c;點擊那個exe文件就下載本地&#xff0c;然后雙擊安裝 安裝nvm 就直接按照窗口提示的下一步就行&#xff0c;如果改了某些地方會不成功&#xf…

數字孿生技術:提升UI交互性與個性化設計

隨著數字化時代的到來&#xff0c;數字孿生技術正在逐漸改變我們的生活和工作方式。數字孿生是一種復制現實世界系統或實體的技術&#xff0c;通過創建數字模型來模擬現實世界中的各種行為和事件。這種技術不僅為人們提供了一個全新的視角來看待和解決問題&#xff0c;同時也為…

內衣專用洗衣機怎么樣?口碑最好的小型洗衣機

隨著人們的生活水平的提升&#xff0c;越來越多小伙伴來開始追求更高的生活水平&#xff0c;一些智能化的小家電就被發明出來&#xff0c;而且內衣洗衣機是其中一個。現在通過內衣褲感染到細菌真的是越來越多&#xff0c;所以我們對內衣褲的清洗頻次會高于普通衣服&#xff0c;…

Spring Boot 3.2發布:大量Java 21的支持上線,改進可觀測性

就在今天凌晨&#xff0c;Spring Boot 3.2正式發布了&#xff01;該版本是在Java 21正式發布之后的重要支持版本&#xff0c;所以在該版本中包含大量對Java 21支持的優化。 下面&#xff0c;我們分別通過Spring官方發布的博文和Josh Long長達80分鐘的介紹視頻&#xff0c;一起…

飛翔的鳥游戲

一.準備工作 首先創建一個新的Java項目命名為“飛翔的鳥”&#xff0c;并在src中創建一個包命名為“com.qiku.bird"&#xff0c;在這個包內分別創建4個類命名為“Bird”、“BirdGame”、“Column”、“Ground”&#xff0c;并向需要的圖片素材導入到包內。 二.代碼呈現 pa…

【醫學圖像處理】超詳細!PET圖像批量預處理

目錄 一、單個PET圖像預處理1、使用[MRIConvert](https://pan.baidu.com/s/1cn3kgeVRir8HvP6HHm0M0Q?pwd5rt5)處理DCM2、MRI和PET數據預處理過程1&#xff09; 打開matlab命令行輸入spm pet&#xff0c;打開SMP12&#xff0c;界面如下2&#xff09; Realign&#xff0c;只需要…

【Vue】插值表達式

作用&#xff1a;利用表達式進行插值渲染 語法&#xff1a;{ { 表達式 } } 目錄 案例一&#xff1a; 案例二&#xff1a; 案例三&#xff1a; ?編輯 注意&#xff1a; 案例一&#xff1a; <!DOCTYPE html> <html lang"en"> <head><me…

項目中如何配置數據可視化展現

在現今數據驅動的時代&#xff0c;可視化已逐漸成為數據分析的主要途徑&#xff0c;可視化大屏的廣泛使用便應運而生。很多公司及政務機構&#xff0c;常利用大屏的手段展現其實力或演示業務&#xff0c;可視化的效果能讓觀者更快速的理解結果并直觀的看到數據展現。因此&#…

加速軟件開發:自動化測試在持續集成中的重要作用!

持續集成的自動化測試 如今互聯網軟件的開發、測試和發布&#xff0c;已經形成了一套非常標準的流程&#xff0c;最重要的組成部分就是持續集成&#xff08;Continuous integration&#xff0c;簡稱CI&#xff0c;目前主要的持續集成系統是Jenkins&#xff09;。 那么什么是持…

教育+AIGC開局之年:教育派作業幫、科技派科大訊飛同路不同道

配圖來自Canva可畫 與往年相比&#xff0c;今年的雙11顯得格外冷清&#xff0c;GMV&#xff08;商品交易總額&#xff09;數據和增長數據無人提及&#xff0c;京東、淘寶天貓、抖音、快手等平臺的火藥味都淡了。一片祥和有序的雙11氛圍中&#xff0c;昔日的K12教育企業與科技企…