Kruskal算法剖析與py/cpp/Java語言實現

Kruskal算法剖析與py/cpp/Java語言實現

    • 一、Kruskal算法的基本概念
      • 1.1 最小生成樹
      • 1.2 Kruskal算法核心思想
    • 二、Kruskal算法的執行流程
    • 三、Kruskal算法的代碼實現
      • 3.1 Python實現
      • 3.2 C++實現
      • 3.3 Java實現
    • 四、算法復雜度分析
      • 4.1 時間復雜度
      • 4.2 空間復雜度
    • 五、Kruskal算法應用場景
      • 5.1 網絡布線
      • 5.2 聚類分析
      • 5.3 電路設計
    • 總結

圖論算法中最小生成樹(Minimum Spanning Tree,MST)問題是一個經典且具有重要實際意義的問題。Kruskal算法作為求解最小生成樹的常用算法之一,以其簡潔的思想和高效的實現,在網絡規劃、電路設計、聚類分析等眾多領域發揮著關鍵作用。本文我將深入剖析Kruskal算法的原理、詳細介紹其執行流程,并分別使用Python、C++和Java三種編程語言進行代碼實現,幫你全面掌握這一經典算法。

一、Kruskal算法的基本概念

1.1 最小生成樹

對于一個連通無向圖 (G=(V, E)),其中 (V) 是頂點集合,(E) 是邊集合,其最小生成樹是一個包含圖中所有頂點的樹狀子圖 (T=(V, E’))((E’ \subseteq E)),并且滿足邊的權值之和最小。最小生成樹具有以下特點:

  • 包含圖中的所有頂點,即頂點數為 (|V|)。
  • 邊數為 (|V| - 1),因為樹的邊數比頂點數少 1。
  • 不存在回路(環),確保其樹狀結構。
  • 邊的權值總和在所有滿足上述條件的子圖中最小。

1.2 Kruskal算法核心思想

Kruskal算法基于貪心策略,其核心思想是:從圖中所有邊中選擇權值最小的邊,若該邊的兩個頂點不在同一個連通分量中,則將這條邊加入到最小生成樹中;重復這個過程,直到最小生成樹包含圖中的所有頂點,或者邊的數量達到 (|V| - 1) 為止。通過不斷選擇局部最優(權值最小且不構成回路的邊),最終得到全局最優的最小生成樹。

二、Kruskal算法的執行流程

  1. 初始化:將圖中的每條邊按照權值從小到大進行排序。同時,初始化一個用于存儲最小生成樹的邊集合 mst_edges,以及一個用于判斷頂點是否在同一個連通分量的并查集數據結構(可以使用數組或更復雜的并查集類實現)。
  2. 遍歷邊:依次遍歷排序后的邊集合,對于每條邊 ((u, v, w))(其中 (u) 和 (v) 是邊的兩個頂點,(w) 是邊的權值):
    • 使用并查集判斷頂點 (u) 和 (v) 是否在同一個連通分量中。如果不在同一個連通分量,說明將這條邊加入最小生成樹不會形成回路,則將該邊加入到 mst_edges 中,并通過并查集將 (u) 和 (v) 所在的連通分量合并。
    • 如果頂點 (u) 和 (v) 已經在同一個連通分量中,說明加入這條邊會形成回路,直接跳過該邊。
  3. 結束條件:當最小生成樹的邊數達到 (|V| - 1) 時,或者遍歷完所有邊后,算法結束。此時,mst_edges 中存儲的邊集合即為圖的最小生成樹。
    Kruskal

三、Kruskal算法的代碼實現

3.1 Python實現

def find(parent, i):if parent[i] == i:return ireturn find(parent, parent[i])def union(parent, rank, x, y):xroot = find(parent, x)yroot = find(parent, y)if rank[xroot] < rank[yroot]:parent[xroot] = yrootelif rank[xroot] > rank[yroot]:parent[yroot] = xrootelse:parent[yroot] = xrootrank[xroot] += 1def kruskalMST(graph):result = []i, e = 0, 0edges = []for u in range(len(graph)):for v, w in enumerate(graph[u]):if w > 0:edges.append((u, v, w))edges.sort(key=lambda item: item[2])parent = []rank = []for v in range(len(graph)):parent.append(v)rank.append(0)while e < len(graph) - 1 and i < len(edges):u, v, w = edges[i]i = i + 1x = find(parent, u)y = find(parent, v)if x != y:e = e + 1result.append((u, v, w))union(parent, rank, x, y)return resultgraph = [[0, 10, 6, 5, 0, 0],[10, 0, 0, 15, 0, 0],[6, 0, 0, 4, 7, 0],[5, 15, 4, 0, 0, 8],[0, 0, 7, 0, 0, 9],[0, 0, 0, 8, 9, 0]
]
print(kruskalMST(graph))

3.2 C++實現

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;class Edge {
public:int src, dest, weight;Edge(int s, int d, int w) : src(s), dest(d), weight(w) {}
};bool compareEdges(const Edge& a, const Edge& b) {return a.weight < b.weight;
}int find(vector<int>& parent, int i) {if (parent[i] == i)return i;return find(parent, parent[i]);
}void unionSet(vector<int>& parent, vector<int>& rank, int x, int y) {int xroot = find(parent, x);int yroot = find(parent, y);if (rank[xroot] < rank[yroot])parent[xroot] = yroot;else if (rank[xroot] > rank[yroot])parent[yroot] = xroot;else {parent[yroot] = xroot;rank[xroot]++;}
}vector<Edge> kruskalMST(vector<vector<int>>& graph) {vector<Edge> edges;for (int u = 0; u < graph.size(); u++) {for (int v = 0; v < graph.size(); v++) {if (graph[u][v] > 0) {edges.push_back(Edge(u, v, graph[u][v]));}}}sort(edges.begin(), edges.end(), compareEdges);vector<int> parent(graph.size());vector<int> rank(graph.size(), 0);for (int i = 0; i < graph.size(); i++) {parent[i] = i;}vector<Edge> result;int e = 0, i = 0;while (e < graph.size() - 1 && i < edges.size()) {Edge next_edge = edges[i++];int x = find(parent, next_edge.src);int y = find(parent, next_edge.dest);if (x != y) {e++;result.push_back(next_edge);unionSet(parent, rank, x, y);}}return result;
}int main() {vector<vector<int>> graph = {{0, 10, 6, 5, 0, 0},{10, 0, 0, 15, 0, 0},{6, 0, 0, 4, 7, 0},{5, 15, 4, 0, 0, 8},{0, 0, 7, 0, 0, 9},{0, 0, 0, 8, 9, 0}};vector<Edge> mst = kruskalMST(graph);for (const auto& edge : mst) {cout << edge.src << " - " << edge.dest << " : " << edge.weight << endl;}return 0;
}

3.3 Java實現

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;class Edge implements Comparable<Edge> {int src, dest, weight;public Edge(int src, int dest, int weight) {this.src = src;this.dest = dest;this.weight = weight;}@Overridepublic int compareTo(Edge other) {return Integer.compare(this.weight, other.weight);}
}class Kruskal {static int find(int[] parent, int i) {if (parent[i] == i)return i;return find(parent, parent[i]);}static void union(int[] parent, int[] rank, int x, int y) {int xroot = find(parent, x);int yroot = find(parent, y);if (rank[xroot] < rank[yroot])parent[xroot] = yroot;else if (rank[xroot] > rank[yroot])parent[yroot] = xroot;else {parent[yroot] = xroot;rank[xroot]++;}}static List<Edge> kruskalMST(int[][] graph) {List<Edge> edges = new ArrayList<>();for (int u = 0; u < graph.length; u++) {for (int v = 0; v < graph.length; v++) {if (graph[u][v] > 0) {edges.add(new Edge(u, v, graph[u][v]));}}}Collections.sort(edges);int[] parent = new int[graph.length];int[] rank = new int[graph.length];for (int i = 0; i < graph.length; i++) {parent[i] = i;}List<Edge> result = new ArrayList<>();int e = 0, i = 0;while (e < graph.length - 1 && i < edges.size()) {Edge nextEdge = edges.get(i++);int x = find(parent, nextEdge.src);int y = find(parent, nextEdge.dest);if (x != y) {e++;result.add(nextEdge);union(parent, rank, x, y);}}return result;}
}public class KruskalAlgorithm {public static void main(String[] args) {int[][] graph = {{0, 10, 6, 5, 0, 0},{10, 0, 0, 15, 0, 0},{6, 0, 0, 4, 7, 0},{5, 15, 4, 0, 0, 8},{0, 0, 7, 0, 0, 9},{0, 0, 0, 8, 9, 0}};List<Edge> mst = Kruskal.kruskalMST(graph);for (Edge edge : mst) {System.out.println(edge.src + " - " + edge.dest + " : " + edge.weight);}}
}

四、算法復雜度分析

4.1 時間復雜度

Kruskal算法的時間復雜度主要由兩部分組成:

  • 對邊進行排序的時間復雜度:假設圖中有 (E) 條邊,使用比較排序算法(如快速排序、歸并排序)對邊按權值排序,時間復雜度為 (O(E \log E))。由于在連通圖中 (E \geq V - 1),所以 (O(E \log E)) 可以近似為 (O(E \log V))。
  • 遍歷邊并判斷連通性和合并連通分量的時間復雜度:在最壞情況下,需要遍歷所有 (E) 條邊,每次遍歷需要使用并查集判斷頂點的連通性和合并連通分量,其時間復雜度近似為 (O(\alpha(V)))((\alpha(V)) 是阿克曼函數的反函數,增長極其緩慢,在實際應用中可近似看作常數時間)。因此,遍歷邊的總時間復雜度為 (O(E \alpha(V))),可近似為 (O(E))。

綜合以上兩部分,Kruskal算法的時間復雜度為 (O(E \log V)),其中 (E) 是邊的數量,(V) 是頂點的數量。

4.2 空間復雜度

Kruskal算法的空間復雜度主要取決于存儲圖的邊集合和并查集數據結構所需的空間:

  • 存儲邊集合:需要存儲圖中的所有邊,邊的數量為 (E),因此存儲邊集合的空間復雜度為 (O(E))。
  • 并查集數據結構:需要存儲每個頂點的父節點信息和秩信息,頂點數量為 (V),所以并查集的空間復雜度為 (O(V))。

綜合起來,Kruskal算法的空間復雜度為 (O(E + V)),在實際應用中,由于 (E \geq V - 1),所以空間復雜度可近似為 (O(E))。

五、Kruskal算法應用場景

5.1 網絡布線

在構建計算機網絡、電力網絡等實際場景中,需要在多個節點之間進行連接,同時要使連接的成本最小。將各個節點看作圖的頂點,節點之間的連接看作邊,邊的權值可以是連接的成本(如鋪設電纜的長度、費用等),通過Kruskal算法可以找到成本最小的網絡連接方案,確保所有節點都能連通且總費用最低。

5.2 聚類分析

在數據聚類問題中,可以將數據點看作圖的頂點,頂點之間的距離(如歐幾里得距離)看作邊的權值。通過Kruskal算法構建最小生成樹,然后從最小生成樹中刪除權值較大的邊,將圖分割成多個連通分量,每個連通分量就對應一個聚類。這種方法可以根據不同的需求,通過調整刪除邊的策略,得到不同數量和規模的聚類結果 。

5.3 電路設計

在集成電路設計中,需要將多個電子元件連接起來,同時要盡量減少連線的長度,以降低電路的成本和功耗。將電子元件看作頂點,元件之間的連接看作邊,邊的權值為連線長度,利用Kruskal算法可以找到連接所有元件的最短連線方案,優化電路設計。

總結

Kruskal算法以其簡潔高效的貪心策略,成為求解最小生成樹問題的經典算法。通過對算法原理、執行流程的詳細講解,以及Python、C++、Java三種編程語言的代碼實現,我們深入理解了Kruskal算法的具體實現方式,事不宜遲,我們不妨找些算法題刷起來吧!

That’s all, thanks for reading!
覺得有用就點個贊、收進收藏夾吧!關注我,獲取更多干貨~

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

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

相關文章

微信小程序返回上一頁監聽

本文實現的是微信小程序在返回上一頁時獲取通知并自定義業務。 最簡單的實現&#xff1a; 使用 wx.enableAlertBeforeUnload() 優點&#xff1a;快速接入 缺點&#xff1a;手勢不能識別、無法自定義彈窗內容&#xff08;僅詢問&#xff09; 方法二&#xff1a; page-conta…

Excel 統計某個字符串在指定區域出現的次數

【本文概要】 Excel 統計某個字符串在指定區域出現的次數&#xff1a; 1、Excel 統計一個單元格內的某字符串的出現次數 2、Excel 統計某一列所有單元格內的某字符串的出現次數 3、Excel 統計某一區域所有單元格內的某字符串的出現次數 1、Excel 統計一個單元格內的某字符串的出…

生物化學:藥品藥物 營養和補充劑信息 第三方認證信息 常見誤區 匯總

常見維生素和礦物質成分表 成分名稱好處副作用&#xff08;超量或敏感情況&#xff09;運作方式推薦日劑量&#xff08;成人&#xff09;劑量說明維生素A&#xff08;視黃醇&#xff09;視力、免疫、皮膚健康過量可致肝損傷、頭痛、脫發調節視網膜功能、細胞分化700–900 g RA…

mock庫知識筆記(持續更新)

文章目錄 mock簡介導入方式參數簡介使用場景&#xff08;待更新&#xff09;常見問題總結&#xff08;待更新&#xff09;Python代碼官網 mock簡介 mock是一個模擬對象庫&#xff0c;具有模擬其他python對象的功能&#xff0c;還能指定模擬對象的返回值和設置模擬對象的屬性。…

扇形 圓形 面積公式

? 一、圓的面積公式 全圓面積&#xff1a; A circle π r 2 A_{\text{circle}} \pi r^2 Acircle?πr2 ? 二、扇形的面積公式&#xff08;兩種制式&#xff09; 弧度制&#xff1a; A sector 1 2 r 2 θ A_{\text{sector}} \frac{1}{2} r^2 \theta Asector?21?r2θ …

怎樣將win11+ubuntu雙系統的ubuntu從機械硬盤遷移至固態硬盤(1)

將 Ubuntu 從機械硬盤遷移到固態硬盤是一個涉及多個步驟的過程。以下是一個基本的遷移指南&#xff1a; 1. 前期準備 1.1 備份數據&#xff1a; 確保你已備份數據&#xff0c;以防止在遷移過程中出現意外導致任何數據丟失。 1.2 固態硬盤安裝&#xff1a; 確保固態硬盤正確…

js中common.js和ECMAScript.js區別

以下是關于 CommonJS 和 ECMAScript Modules&#xff08;ESM&#xff09;的詳細對比分析&#xff0c;包含底層原理和示例說明&#xff1a; &#x1f9e9; 核心差異對比表 特性CommonJSES Modules來源Node.js 社區規范ECMAScript 語言標準加載方式動態加載&#xff08;運行時解…

玻纖效應的時序偏差

隨著比特率繼續飆升&#xff0c;光纖編織效應時序偏移正成為一個越來越嚴重的問題。對于 5GB/s 及以上的信號傳輸速率&#xff0c;它實際上會毀了您的一天。例如&#xff0c;左圖顯示由于 12.7 英寸的纖維編織效果&#xff0c;5GB/s 的接收眼完全閉合。使用 Agilent ADS 軟件進…

異步上傳石墨文件進度條前端展示記錄(采用Redis中String數據結構實現)

事件起因是客戶現場需要從石墨文檔中獲取文件信息&#xff0c;文件信息存在存在多個&#xff0c;進行批量上傳。為了用戶的友好型體驗&#xff0c;需要做進行條展示的方式&#xff0c;具體實現見下文… 上傳流程介紹 石墨文檔支持從鏈接&#x1f517;方式獲取文件信息&#xf…

3D建模的全景圖譜:從55個工具到元宇宙的數字革命

3D建模已從專業工程師的工具箱演變為全民創作的數字語言。從代碼驅動的精確建模到AI自動生成紋理&#xff0c;從開源協作到程序化生成城市&#xff0c;技術正重塑我們創造虛擬世界的方式。本文將系統解析55個核心3D建模工具/插件&#xff0c;涵蓋在線編輯器、開源軟件、程序化生…

jsrpc進階模式 秒殺js前端逆向問題 burp聯動進行爆破

案例演示 思路就是 這個 jsrpc遠程加載加密函數的方法就是 在js代碼中進行插入一個 遠程加載的代碼 從而實現 &#xff1a; 第一步還是使用 js_tools 進行 查找算法的位置 這個可以幫助我們找到明文>密文 加密算法函數的位置 因為這個需要我們進行js前端代碼的修改 所以…

基于BERT-Prompt的領域句子向量訓練方法

基于BERT-Prompt的領域句子向量訓練方法 一、核心原理:基于BERT-Prompt的領域句子向量訓練方法 論文提出一種結合提示學習(Prompt Learning)和BERT的領域句子向量訓練方法,旨在解決裝備保障領域文本的語義表示問題。核心原理如下: 以下通過具體例子解釋傳統詞向量方法和…

Python PyMySQL

1.PyMySQL是什么 是Python操作mysql的一個包 2.PyMySQL使用基本步驟 2.1 創建連接 conn pymysql.connect(host10.248.53.148,password123456,port3306,userroot,databasetest_database,charsetutf8)2.2 游標 2.2.1 什么是游標 游標實際上是一種能從包括多條數據記錄的結果…

OC—UI學習-1

OC—UI學習 UILabel UILabel是UIKit框架中的一個類Label主要參數 text&#xff1a;文本frame&#xff1a;位置框架backgroundcolor&#xff1a;背景顏色textAlignment&#xff1a;設置文本在Label中的位置textColor&#xff1a;文本顏色shadowColor&#xff1a;陰影顏色shado…

【應用密碼學】實驗七 Hash函數——SM3

一、實驗要求與目的 理解哈希函數的基本原理及在密碼學中的應用&#xff1b;掌握國密哈希標準 SM3 的算法結構&#xff1b;編程實現 SM3 摘要算法&#xff0c;包括消息填充、消息擴展、壓縮函數及摘要輸出&#xff1b;對中間變量 W、W′ 和 A~H 的迭代過程進行可視化&#xff…

進行性核上性麻痹護理之道:助力患者舒適生活

進行性核上性麻痹是一種緩慢進展的神經退行性疾病&#xff0c;主要影響患者的運動、語言和吞咽功能&#xff0c;給日常生活帶來諸多不便。除了遵醫囑接受藥物或物理治療&#xff0c;科學的健康護理對延緩病情發展、提升生活質量尤為重要。 運動康復是護理的關鍵環節。由于患者常…

5G 核心網中 NRF 網元的功能、接口及參數詳解

引言 在 5G 核心網的架構體系里,網絡存儲功能(Network Repository Function,NRF)占據著關鍵地位,承擔著核心網網絡功能(Network Function,NF)的注冊、發現以及服務管理等重要任務,為整個 5G 網絡的高效穩定運行提供了堅實支撐。接下來,讓我們深入剖析 NRF 網元在注冊…

HUAWEI交換機配置鏡像口驗證(eNSP)

技術術語&#xff1a; 流量觀察口&#xff1a;就是我們常說的鏡像口&#xff0c;被觀察的流量的引流目的端口 流量源端口&#xff1a;企業生產端口&#xff0c;作為觀察口觀察對象。 命令介紹&#xff1a; [核心交換機]observe-port [觀察端口ID或編號&#xff08;數字&am…

Spring AI Alibaba 發布企業級 MCP 分布式部署方案

作者&#xff1a; 影子&#xff0c;劉宏宇&#xff0c;劉軍 Spring AI 通過集成 MCP 官方的 java sdk&#xff0c;讓 Spring Boot 開發者可以非常方便的開發自己的 MCP 服務&#xff0c;把自己企業內部的業務系統通過標準 MCP 形式發布為 AI Agent 能夠接入的工具&#xff1b;…

Redis實戰-緩存篇(萬字總結)

前言&#xff1a; 今天結合黑馬點評這個項目&#xff0c;講下有關Redis緩存的一些內容&#xff0c;例如緩存更新策略&#xff0c;緩存穿透&#xff0c;雪崩和擊穿等。 今日所學&#xff1a; 什么是緩存緩存更新策略緩存穿透緩存雪崩緩存擊穿緩存工具封存 目錄 1.什么是緩存…