Kruskal和Prim

news2024/11/13 6:44:17

Kruskal和Prim是两种常用的求解最小生成树(Minimum Spanning Tree, MST)的算法。它们用于在一个加权无向图中找到一棵包含所有顶点且总权重最小的树。

Kruskal算法

介绍
Kruskal算法采用贪心策略,从小到大选择边,并检查是否形成环。如果形成环,则不选择该边,否则选择该边。Kruskal算法通常使用并查集(Union-Find)来检测环。

步骤

  1. 将所有边按权重从小到大排序。
  2. 初始化一个空的最小生成树。
  3. 依次选择排序后的边,如果加入该边不形成环,则将该边加入最小生成树。
  4. 当最小生成树包含所有顶点时,算法结束。

特点

  • 适用于稀疏图(边较少)。
  • 时间复杂度为O(E log E),其中E为边的数量。
#include <stdio.h>
#include <stdlib.h>

#define V 4  // 顶点数量

// 定义边结构体
typedef struct Edge {
    int src, dest, weight;
} Edge;

// 并查集结构体
typedef struct Subset {
    int parent, rank;
} Subset;

Edge edge[V * (V - 1) / 2];  // 存储所有边
Subset subsets[V];           // 存储所有子集
int E;  // 边的数量

// 查找根节点
int find(Subset subsets[], int i) {
    if (subsets[i].parent != i)
        subsets[i].parent = find(subsets, subsets[i].parent);
    return subsets[i].parent;
}

// 合并两个子集
void unionSubsets(Subset subsets[], int x, int y) {
    int xroot = find(subsets, x);
    int yroot = find(subsets, y);

    if (subsets[xroot].rank < subsets[yroot].rank)
        subsets[xroot].parent = yroot;
    else if (subsets[xroot].rank > subsets[yroot].rank)
        subsets[yroot].parent = xroot;
    else {
        subsets[yroot].parent = xroot;
        subsets[xroot].rank++;
    }
}

// 比较函数,用于排序边
int compare(const void *a, const void *b) {
    return (*(Edge *)a).weight - (*(Edge *)b).weight;
}

// Kruskal算法
void kruskalMST(int graph[V][V]) {
    int i, u, v, w, x, y;
    Edge result[V];  // 存储最小生成树的边
    int e = 0;  // 已选择的边数量

    // 初始化边数组
    for (i = 0; i < V - 1; i++) {
        for (j = i + 1; j < V; j++) {
            if (graph[i][j]) {
                edge[E].src = i;
                edge[E].dest = j;
                edge[E].weight = graph[i][j];
                E++;
            }
        }
    }

    // 排序边
    qsort(edge, E, sizeof(Edge), compare);

    // 初始化并查集
    for (i = 0; i < V; i++) {
        subsets[i].parent = i;
        subsets[i].rank = 0;
    }

    printf("Edge \tWeight\n");
    for (i = 0; i < E; i++) {
        u = edge[i].src;
        v = edge[i].dest;
        w = edge[i].weight;
        x = find(subsets, u);
        y = find(subsets, v);

        if (x != y) {
            result[e].src = u;
            result[e].dest = v;
            result[e].weight = w;
            e++;
            unionSubsets(subsets, x, y);
            printf("%d - %d \t%d \n", u, v, w);
        }

        // 如果最小生成树包含所有顶点,则结束
        if (e == V - 1)
            break;
    }
}

int main() {
    int graph[V][V] = {
        {0, 2, 0, 6},
        {2, 0, 3, 8},
        {0, 3, 0, 5},
        {6, 8, 5, 0}
    };

    kruskalMST(graph);

    return 0;
}

Prim算法

介绍
Prim算法也采用贪心策略,从任意一个顶点开始,逐步扩展最小生成树。每次选择权重最小的连接树中顶点和树外顶点的边。Prim算法通常使用优先队列(例如最小堆)来高效选择最小边。

步骤

  1. 从任意一个顶点开始,将其加入最小生成树。
  2. 初始化一个优先队列,存储所有连接树中顶点和树外顶点的边。
  3. 从优先队列中取出权重最小的边,将对应的顶点加入最小生成树。
  4. 更新优先队列,加入新的连接树中顶点和树外顶点的边。
  5. 重复步骤3和4,直到最小生成树包含所有顶点。

特点

  • 适用于稠密图(边较多)。
  • 时间复杂度为O(E log V),其中E为边的数量,V为顶点的数量。
#include <stdio.h>
#include <limits.h>
#include <stdbool.h>

#define V 5  // 顶点数量

// 找到最小权重边的索引
int minKey(int key[], bool mstSet[]) {
    int min = INT_MAX, min_index;

    for (int v = 0; v < V; v++)
        if (mstSet[v] == false && key[v] < min)
            min = key[v], min_index = v;

    return min_index;
}

// 打印最小生成树
void printMST(int parent[], int graph[V][V]) {
    printf("Edge \tWeight\n");
    for (int i = 1; i < V; i++)
        printf("%d - %d \t%d \n", parent[i], i, graph[i][parent[i]]);
}

// Prim算法
void primMST(int graph[V][V]) {
    int parent[V];  // 存储构建的最小生成树
    int key[V];     // 用于选择最小权重边
    bool mstSet[V]; // 表示顶点是否包含在最小生成树中

    // 初始化所有键值为无穷大
    for (int i = 0; i < V; i++)
        key[i] = INT_MAX, mstSet[i] = false;

    // 从第一个顶点开始,键值为0
    key[0] = 0;
    parent[0] = -1;  // 第一个顶点是根节点

    // 构建最小生成树
    for (int count = 0; count < V - 1; count++) {
        // 从未处理的顶点中选择键值最小的顶点
        int u = minKey(key, mstSet);

        // 将选择的顶点加入最小生成树
        mstSet[u] = true;

        // 更新相邻顶点的键值
        for (int v = 0; v < V; v++)
            if (graph[u][v] && mstSet[v] == false && graph[u][v] < key[v])
                parent[v] = u, key[v] = graph[u][v];
    }

    // 打印构建的最小生成树
    printMST(parent, graph);
}

int main() {
    int graph[V][V] = {
        {0, 2, 0, 6, 0},
        {2, 0, 3, 8, 5},
        {0, 3, 0, 0, 7},
        {6, 8, 0, 0, 9},
        {0, 5, 7, 9, 0}
    };

    primMST(graph);

    return 0;
}

区别

  1. 驱动方式不同

    • Kruskal算法是边驱动的算法。它首先将所有边按照权重从小到大排序,然后依次选择权值最小的边,如果选择的边不会形成环路,则将其加入生成树中。
    • Prim算法是顶点驱动的算法。它从一个初始顶点开始,每次选择距离当前生成树最近的顶点,并将其加入生成树中,直到所有顶点都被加入。
  2. 数据结构实现不同

    • Kruskal算法通常使用并查集来检测是否形成环路,以保证生成树的连通性。
    • Prim算法通常使用优先队列或最小堆来实现,以快速找到距离当前生成树最近的顶点。
  3. 时间复杂度不同

    • Kruskal算法的时间复杂度为O(E log E),其中E是边的数量,因为它需要对所有边进行排序。
    • Prim算法的时间复杂度在稠密图(边数量接近顶点数量的平方)上为O(V^2),其中V是顶点的数量;在稀疏图(边数量远小于顶点数量的平方)上,Prim算法的时间复杂度可以优化到O(E log V)。
  4. 适用场景不同

    • Kruskal算法更适合处理稀疏图,因为其时间复杂度与边的数量相关,而稀疏图的边数量相对较少。
    • Prim算法更适合处理稠密图,因为其时间复杂度不受边的数量的影响。

优缺点

Kruskal算法

  • 优点:算法简单易懂,实现起来较为容易,且对于稀疏图来说效率较高。
  • 缺点:需要对所有边进行排序,因此在稠密图中效率较低。

Prim算法

  • 优点:在稠密图中效率较高,且可以并行化处理,提高计算效率。此外,Prim算法的思想较为简单明了,容易理解和实现。
  • 缺点:需要对每个节点与其相关的边进行检查,导致在稀疏图中的性能较差。同时,Prim算法在实现过程中需要使用优先队列等数据结构,对图的表示和操作有一定的要求和限制。

综上所述,Kruskal算法和Prim算法各有其优缺点和适用场景。在实际应用中,应根据具体问题的特点和图的稠密程度来选择适合的算法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2237717.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaWeb合集23-文件上传

二十三 、 文件上传 实现效果&#xff1a;用户点击上传按钮、选择上传的头像&#xff0c;确定自动上传&#xff0c;将上传的文件保存到指定的目录中&#xff0c;并重新命名&#xff0c;生成访问链接&#xff0c;返回给前端进行回显。 1、前端实现 vue3AntDesignVue实现 <tem…

Java项目实战II基于Spring Boot的药店管理系统的设计与实现(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。 一、前言 随着医疗行业的快速发展和人们对健康需…

「撸一手好代码」设计模式之接口隔离原则

「撸一手好代码」设计模式之接口隔离原则 什么是接口隔离原则 接口隔离原则&#xff08;Interface Segregation Principle, ISP&#xff09;指出&#xff0c;客户端不应该依赖它不使用的接口。换句话说&#xff0c;一个类对另一个类的依赖应该建立在最小的接口上。接口的设计应…

在 WPF 中,绑定机制是如何工作的?WPF数据绑定机制解析

在WPF&#xff08;Windows Presentation Foundation&#xff09;中&#xff0c;数据绑定机制是其核心功能之一&#xff0c;广泛用于连接应用程序的UI&#xff08;用户界面&#xff09;和应用程序的业务逻辑层。数据绑定允许你将UI元素与数据源&#xff08;如对象、集合或其他数…

线性代数:Matrix2x2和Matrix3x3

今天整理自己的框架代码&#xff0c;将Matrix2x2和Matrix3x3给扩展了一下&#xff0c;发现网上unity数学计算相关挺少的&#xff0c;所以记录一下。 首先扩展Matrix2x2&#xff1a; using System.Collections; using System.Collections.Generic; using Unity.Mathemati…

字节青训-小F的永久代币卡回本计划、

目录 一、小F的永久代币卡回本计划 问题描述 测试样例 解题思路&#xff1a; 问题理解&#xff1a; 数学公式&#xff1a; 代码实现&#xff1a; 最终代码&#xff1a; 运行结果&#xff1a; 二、构造特定数组的逆序拼接 问题描述 测试样例 解题思路&#xff1a;…

PGMP-串串0203 项目集管理绩效域战略一致性

1.项目集管理绩效域 2.战略一致性 战略一致性包含内容商业论证BC项目集章程项目集路线图环境评估项目集风险管理策略 前期formulation sub-phaseplanning sub-phase组织的战略计划项目集风险管理策略项目集管理计划商业论证BC项目集章程项目集路线图环境评估

使用ThorUi

摘要&#xff1a; 官网 今天遇到一个老项目&#xff0c;使用的是ThorUi组件库&#xff01;之前没有用过这组件库&#xff0c;所以记录一下不同框架是使用情况&#xff01; ThorUI 是一个基于 Thorium 的 UI 框架&#xff0c;用于构建跨平台的桌面应用程序。如果你打算使用 Thor…

【activiti工作流源码集成】springboot+activiti+mysql+vue+redis工作流审批流集成整合业务绑定表单流程图会签驳回

工作流集成实际项目案例&#xff0c;demo提供 源码获取方式&#xff1a;本文末个人名片直接获取。 前言 activiti工作流引擎项目&#xff0c;企业erp、oa、hr、crm等企事业办公系统轻松落地&#xff0c;请假审批demo从流程绘制到审批结束实例。 一、项目形式 springbootvue…

【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案

作者&#xff1a;CSDN-PleaSure乐事 欢迎大家阅读我的博客 希望大家喜欢 使用环境&#xff1a;WebStorm 目录 问题概述 原因 解决方案 解决方法 潜在问题修改 最终效果呈现 额外内容 管理员界面路由配置 WebStorm背景更换 法一&#xff1a; 法二&#xff1a; 问题概…

布谷直播源码部署服务器关于数据库配置的详细说明

布谷直播源码搭建部署配置接口数据库 /public/db.php&#xff08;2019年8月后的系统在该路径下配置数据库&#xff0c;老版本继续走下面的操作&#xff09; 在项目代码中执行命令安装依赖库&#xff08;⚠️注意&#xff1a;如果已经有了vendor内的依赖文件的就不用执行了&am…

Spring中的过滤器和拦截器

Spring中的过滤器和拦截器 一、引言 在Spring框架中&#xff0c;过滤器&#xff08;Filter&#xff09;和拦截器&#xff08;Interceptor&#xff09;是实现请求处理的两种重要机制。它们都基于AOP&#xff08;面向切面编程&#xff09;思想&#xff0c;用于在请求的生命周期…

Day16二叉树的中序遍历

给定一个二叉树的根节点 root &#xff0c;返回它的中序遍历 。 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(i…

RT-DETR实战TT100K中国交通标志识别

本文采用RT-DETR作为核心算法框架&#xff0c;结合PyQt5构建用户界面&#xff0c;使用Python3进行开发。RT-DETR以其高效的实时检测能力&#xff0c;在多个目标检测任务中展现出卓越性能。本研究针对TT100K交通标志数据集进行训练和优化&#xff0c;该数据集包含丰富的TT100K交…

图像信号处理器(ISP,Image Signal Processor)详解

简介&#xff1a;个人学习分享&#xff0c;如有错误&#xff0c;欢迎批评指正。 图像信号处理器&#xff08;ISP&#xff0c;Image Signal Processor&#xff09; 是专门用于处理图像信号的硬件或处理单元&#xff0c;广泛应用于图像传感器&#xff08;如 CMOS 或 CCD 传感器&a…

js基础篇笔记 (万字速通)

此笔记来自于黑马程序员,仅供笔者复习 JavaScript 基础 - 第1天 了解变量、数据类型、运算符等基础概念&#xff0c;能够实现数据类型的转换&#xff0c;结合四则运算体会如何编程。 体会现实世界中的事物与计算机的关系理解什么是数据并知道数据的分类理解变量存储数据的“容…

【GPTs】EmojiAI:轻松生成趣味表情翻译

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AIGC | GPTs应用实例 文章目录 &#x1f4af;GPTs指令&#x1f4af;前言&#x1f4af;EmojiAI主要功能适用场景优点缺点 &#x1f4af;小结 &#x1f4af;GPTs指令 中文翻译&#xff1a; 此 GPT 的主要角色是为英文文本提供幽默…

H.264/H.265播放器EasyPlayer.js无插件H5播放器关于WASM的压缩优化

在当今的Web开发领域&#xff0c;流媒体播放器的性能和效率至关重要&#xff0c;尤其是在处理大型视频文件和高分辨率视频流时。EasyPlayer.js RTSP播放器作为一款先进的流媒体播放器&#xff0c;它在WebAssembly&#xff08;WASM&#xff09;的压缩优化方面表现出色&#xff0…

Unity Shader分段式血条

Unity Shader分段式血条 前言项目ASE连线 前言 要给单位加一个类似LOL的分段式血条&#xff0c;用ASE实现并记录一下。里面加了旋转和颜色的渐变。 项目 ASE连线

基于 STM32 的天气时钟项目中添加天气数据的网络获取功能

基于 STM32 的天气时钟项目中添加天气数据的网络获取功能&#xff0c;您需要确保您的开发环境具备网络连接能力。这里以 ESP8266 Wi-Fi 模块为例&#xff0c;详细说明如何实现网络获取天气数据的功能。 1. 硬件连接 连接 ESP8266 模块 请参考以下连接方式&#xff0c;将 ESP82…