最小生成树—Prim算法和Kruskal算法

Prim算法 与 Kruskal算法 求最小生成树 一、Prim算法 普利姆(Prim)算法适用于求解无向图中的最小生成树(Minimum Cost Spanning Tree)。下面是Prim算法构造最小生成树的过程图解。                            &nbsp... 阅读详情

本文主要讨论基于求最小生成树的两种算法—Prim算法和Kruskal算法
主要说说其思想,附代码解释,有问题请留言

延时的Prim算法

  1. 思想:每一步为最小生成树的成长增加一条最短的边。
    分析:
    1>将所有的顶点分为两部分,一部分是逐渐生长的最小生成树(可以用队列来存储),一部分是逐渐减少的非最小生成树(用marked来标记);
    2>还有一个队列维护的边,自然就是存放连接这两部分的边(横切边),每次生长,都在横切边的队列中,取出最小的边加入到最小生成树中;
    3>加入某个顶点和边之后,相应的修改横切边的队列(因为树和非树已经发生变化)。
  2. 如图:
    最小生成树
  3. 代码

注:代码中所使用到的MinPQ类没有什么特别的,就是提供最小值的优先队列数据结构。

package minSpanningTree;

import java.util.LinkedList;
import java.util.Queue;

/**
  *延时的Prim算法,维护两个队列和一个布尔型数组
  *<p>横切边队列:用于维护最小生成树和非最小生成树两个部分之间的连线,
  *并为最小生成树生成横切边的最小值,加入到最小生成树中
  *<p>布尔型数组则是最小生成树的生长过程路迹
  * @author  luoz 
  * @date 2016年9月21日 下午10:24:54 
**/
public class LazyPrinmMST {

    private MinPQ<Edge> pq; //横切边队列
    private Queue<Edge> tree;   //最小生成树队列
    private boolean[] marked;   //最小生成树的顶点

    /**
     * 传入无向带权值图g,构造最小生成树序列
     * @param g
     */
    public LazyPrinmMST(EdgeGraph g)
    {
        /*初始化*/
        marked = new boolean[g.V()];
        tree = new LinkedList<Edge>();
        pq = new MinPQ<>();

        /*从0顶点开始,增加所有与0顶点相连的所有边到pq队列中*/
        visit(g,0);

        /*只要还有一个顶点未被标记的边,就继续将那个顶点以及其与最小生成树最小的横切边加入到最小生成树中*/
        while(!pq.isEmpty())
        {
            /*每一步都为最小生成树增加一个横切边的最小值*/
            Edge e = pq.delMin();
            /*分析最小横切边*/
            int v = e.either();
            int w = e.other(v);
            /*若两个顶点均是被标记了的,此边为无效边*/
            if(marked[v] && marked[w])
                continue;
            /*否则加入到最小生成树的队列中*/
            tree.add(e);

            /*加入一条边后,因为最小生成树和非最小生成树两个部分都已经变化,所以也需要更新横切边队列,*/
            if(!marked[v]) 
                visit(g,v);
            if(!marked[w])
                visit(g,w);
        }
    }

    /**
     * 维护横切边队列
     * 传入参数无向带权值图g,访问到的顶点v
     * @param g
     * @param v
     */
    private void visit(EdgeGraph g,int v)
    {       
        marked[v] = true;   //标记顶点为已访问
        /**
         * 因为在最小生成树中,每生成一个顶点就需要将其顶点的所有边
         * 其中一个顶点已经被标记了的边就不需要添加,因为这条边的两个顶点均在最小生成树中
         * */
        for(Edge e : g.adj(v))  
            if(!marked[e.other(v)])
                pq.insert(e);               
    }

    /*输出最小生成树的序列*/
    public Iterable<Edge> tree()
    {
        return tree;
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        Edge e1 = new Edge(0,1,100);
        Edge e2 = new Edge(0,1,200);
        Edge e3 = new Edge(0,2,300);
        Edge e4 = new Edge(0,2,400);

        EdgeGraph g = new EdgeGraph(3);
        g.addEdge(e1);
        g.addEdge(e2);
        g.addEdge(e3);
        g.addEdge(e4);

        LazyPrinmMST l = new LazyPrinmMST(g);
        System.out.println(l.tree());
    }

}

即时的Prim算法

  1. 思想:由延时的Prim算法我们可以知道,MinPQ队列保存了所有的横切边,但是实际上我们真正需要的不可能是所有的横切边,相反,我们对于横切边的1最小值,我们是肯定要加入到最小生成树中的(即使是延时版本中)
  2. 如图:
    即时Prim
  3. 代码:
package minSpanningTree;

import java.util.LinkedList;
import java.util.Queue;

/**
  *最小生成树的Prim算法即时实现:由Prim算法的延时实现可以知道,主要是把全部的顶点
  *看为两个部分:最小生成树部分和非最小生成树部分。在维护横切边队列的同时,保存了所有两个部分相连的边
  *<p>在即时版本中,我们维护了两个数组和一个队列,还有一个布尔型数组
  *<p>队列中只维护了两个部分相连的最小的边,因为即使在延时版本中,这条最小的边也必然迟早会加入到最小生成树中
  *<p>同时增加了一个Edge数组,保存不断增长的最小边(树),
  *一个Double数组保存权重,用于不断比较树和非树的更短边,并将更短边不断更新到Edge数组中
  *
  * @author  luoz 
  * @date 2016年9月22日 下午3:28:10 
**/
public class PrimMST {

    private boolean[] marked;   //边在树中则为true
    private IndexMinPQ<Double> pq;  //有效的横切边
    private Edge[] edgeTo;  //距离最小生成树最近的边
    private double[] distTo;    //distTo[w] = edgeTo[w].weight()

    public PrimMST(EdgeGraph g)
    {
        marked = new boolean[g.V()];
        pq = new IndexMinPQ<Double>(g.V());
        edgeTo = new Edge[g.V()];
        distTo = new double[g.V()];

        /*将每一个顶点距离树的距离都初始化为无穷大*/
        for(int i = 0;i<g.V();i++)
            distTo[i] = Double.POSITIVE_INFINITY;//double POSITIVE_INFINITY = 1.0 / 0.0

        distTo[0] = 0.0;
        pq.insert(0,0.0);

        while(!pq.isEmpty())
        {
            //延时实现是对每一条不在树中的边都进行维护,在即时实现中,只对最小权值的边进行维护
            visit(g,pq.delMin());
        }

    }

    private void visit(EdgeGraph g,int v)
    {
        marked[v] = true;
        /*循环每一个与v顶点(也可以看作是树)相连的边,得出最短的边并加入到队列pq中*/
        for(Edge e :g.adj(v))
        {
            int w = e.other(v);

            //marked[v]已经被标记true了
            if(marked[w])
                continue;

            /*distTo初始为无穷大,循环过程中,不断地更新与顶点v最近的边*/
            if(e.weight() < distTo[w])
            {
                //连接树的边也要增加或者是修改
                edgeTo[w] = e;

                distTo[w] = e.weight();

                /*发现了更小的边,假如这个边的顶点,已经包含在队列中,那么就更新这个顶点的边的最小值,否则加入到队列中*/
                if(pq.contains(w))  //可能两个顶点存在两条不同权值的边
                    pq.change(w, distTo[w]);
                else
                    pq.insert(w, distTo[w]);
            }
        }
    }

    public Iterable<Edge> edges() {
        Queue<Edge> mst = new LinkedList<Edge>();
        for (int v = 0; v < edgeTo.length; v++) {
            Edge e = edgeTo[v];
            if (e != null) {
                mst.add(e);
            }
        }
        return mst;
    }

    public double weight() {
        double weight = 0.0;
        for (Edge e : edges())
            weight += e.weight();
        return weight;
    }

}

Kruskal算法

  1. 思想:每次取所有边中的一个最小值加入到最小生成树中,直到所有顶点都在树中为止。
    分析:Prim算法可以说是范围由小到大,因为,Prim算法是将所有顶点分为树和非树部分,树部分不断增长;而Kruskal算法一开始就是对所有顶点所有边进行筛选,在其中选出最小值加入到树中,自然是由稀疏到密集。
    2.代码:
package minSpanningTree;

import java.util.LinkedList;
import java.util.Queue;
/**
  *Kruskal算法主要思想:一次性就将全部的边加入到队列中,然后依次按照权值处理它们
  *最小生成树就是依次取最小值,每次取值,查看该边是否有效(即两个顶点是否都在树中)
  * @author  luoz 
  * @date 2016年9月22日 下午4:42:46 
**/
public class KruskalMST {

    //生出的树的队列
    private Queue<Edge> mst;
    //最小生成树的权值和
    private double weight;

    public KruskalMST(EdgeGraph g)
    {
        mst = new LinkedList<Edge>();
        //初始化一个队列(MinPQ,主要用于求出队列中的最小值的边1)
        MinPQ<Edge> pq = new MinPQ<Edge>();
        //将所有边加入到队列中
        for (Edge e : g.edges()) {
            pq.insert(e);
        }

        //这个并不特殊,UF类是一个检测顶点是否有相连的类
        UF uf = new UF(g.V());

        //判断条件自然是队列为空,并且确认所有的顶点都加入到了mst队列中
        while(!pq.isEmpty() && mst.size() < g.V()-1)
        {
            Edge e = pq.delMin();
            int v = e.either();
            int w = e.other(v);

            //判断v,w两个顶点是否已经相连,因为最开始的两个顶点,必然是没有相连的。(相连意味着已经加入到mst中了)
            if(uf.connected(v, w))
                continue;
            uf.union(v, w);
            mst.add(e);
            weight += e.weight();
        }
    }

    public Iterable<Edge> edges()
    {
        return mst;
    }

    public double weight()
    {
        return weight;
    }
}

附加代码
MinPQ.java,IndexMinPQ.java:http://algs4.cs.princeton.edu/20sorting/
UF.java:http://algs4.cs.princeton.edu/10fundamentals/

图的最小生成树之Prim算法及Kruskal算法 最小生成树 定义:无向图连通图G中,由所有顶点构成且总价值(连接权值和)最低的一棵树(拓扑结构)称为一个最小生成树。 最小生成树顶点为|V|个,边数为|V|-1,没有圈。 对任一生成树T,如果将图中一条不属于T的边添加至T,则会产生一个圈,从该圈中除去任意一条边,则会又恢复成生成树。 下图为一示例: 对于上面的无向有权连通图,其最小生成树为: 解决最小生成树问题有两种算法Prim算法和... 阅读详情

相关推荐

【图论】最小生成树算法(prim和kruskal详解及对比)

目录一.最小生成树之primprimprim算法primprimprim完整代码(计算最短距离并输出路径)堆优化版本二.最小生成树之kruskalkruskalkruskal算法kruskalkruskalkruskal完整代码(计算最短距离并输出路径)三.primprimprim和kruskalkruskalkruskal相对比1.1.1.时间上2.2.2.空间上3.3.3.USACO07DEC...

繁凡さん的博客 5000

最小生成树详解

最小生成树来啦!

m0_69349401的博客 1万+

最小生成树——kruskal算法和prim算法

1.最小生成树定义 在一张带权的无向连通图中,各边权和最小的一颗生成树即为最小生成树。 2.最小生成树的应用价值 在现实生活中,很多布线问题,通线网络等问题,都可以直接或者间接的转化成最小生成树的问题去给出花费最小的方案。 3.计算最小生成树的两种算法 计算最小生成树可以采用两种方式,即Kruscarl算法和Prim算法。这两种算法都采用了贪心策略。 看过的一本书上解释说,这两...

Jane_96的博客 3022

最小生成树及扩展应用

最小生成树,最小瓶颈树,次小生成树

EQUINOX1的博客 2653

C++最小生成树(kruskal算法,prim算法)

生成树是一种特殊的连通子图,它在保持图中所有顶点的同时,只包含了构成一棵树的边数,即n-1条边,其中n是图中的顶点数量。生成树是无环的,并且是连通的,这意味着通过生成树可以从任何一个顶点到达其他任何顶点,而不需要回溯或形成环路。权值最小的生成树称为最小生成树。

LXCliuxingchen的博客 720

最小生成树(prim算法,kruskal算法)

对于边上有权的图来说,边权值和最小的生成树叫做这个图的最小生成树。如果一个图的边权值都不相同那么最小生成树是唯一的。 求无向图的最小生成树主要有prim算法和kruskal算法两个。 prim算法思想:设有两个点的集合:U和T,整个过程就是把T中的点不断放进U中,但是次序影响了树的形成,最佳的次序就是最小生成树的产生基础。从U选一个点q1,从T中选一个点q2,使得形成的边的权最小,将q2并入U

theArcticOcean 2824

C++ Kruskal算法

最小生成树之kruskal(克鲁斯卡尔)算法 kruskal算法:同样解决最小生成树的问题,和prim算法不同,kruskal算法采用了边贪心的策略,思想要比prim算法简单。 算法基本思想:在初始状态时隐去图中的所有边,这样图中每个顶点都自成一个连通块。之后执行下面的步骤: (1)对所有的边按边权从小到大进行排序; (2)按边权从小到大测试所有边,如果当前测试边所连接的两个顶点不在同一个连通块中...

weixin_43869906的博客 991

最小生成树-prim、kruskal算法

学习之前建议温习一下迪杰斯特拉算法和并查集~先简单认识下最小生成树:最小生成树是,即:以最小的成本(边的权值)将图中所有节点链接到一起。图中有n个节点,那么一定可以用n-1条边将所有节点连接到一起。那么就是最小生成树算法的任务所在。下面我们以一道模板题来讲解如何解决这个问题~~

qq_73704268的博客 1001

图的最小生成树——Kruskal算法

Kruskal算法的基本思想用伪代码描述如下:1. 初始化:U=V;TE={ }; 2. 重复下述操作直到T中的连通分量个数为1: 2.1 在E中寻找最短边(u,v); 2.2 如果顶点u、v位于T的两个不同连通分量,则 2.2.1 将边(u,v)并入TE; 2.2.2 将这两个连通分量合为一个; 2.3 标记边(u,v),使得(u...

arthu6的博客 816

LVGL9.2移植至正点原子阿波罗STM32F429开发板

LVGL(Light and Versatile Graphics Library)是一个开源的图形库,旨在为嵌入式系统提供高效、灵活的图形用户界面(GUI)解决方案。它具有小巧的内存占用和高性能的渲染能力,支持多种硬件平台,包括单片机、DSP 和 ARM 处理器等。LVGL 支持丰富的控件(如按钮、标签、图标、滚动条等),并提供强大的主题、样式和动画功能,使得开发者能够轻松设计出美观且响应迅速的界面。

m0_51149752的博客 3174

手把手教你搞定JBI投稿:从Statement of Significance到Declaration Statement的保姆级避坑指南

本文提供了一份详细的JBI投稿指南,重点解析Statement of Significance和Declaration of Interests的撰写技巧,帮助研究者避开常见格式陷阱。通过实战案例和检查清单,确保投稿符合JBI的学术严谨性和临床转化价值要求,提升稿件通过率。

weixin_29278805的博客 626

算法之克鲁斯卡尔(Kruskal)算法

克鲁斯卡尔(Kruskal)算法 克鲁斯卡尔(Kruskal)算法,是用来求加权连通图的最小生成树的算法。 基本思想:按照权值从小到大的顺序选择n-1条边,并保证这n-1条边不构成回路 具体做法:首先构造一个只含n个顶点的森林,然后依权值从小到大从连通网中选择边加入到森林中,并使森林中不产生回路,直至森林变成一棵树为止 克鲁斯卡尔算法在所有连接森林的两个不同树的边里面,寻找权值最小的边将最小的边加入一个不相交的集合来进行维护,每次加入时判断该边的起始顶点与结束顶点是否属于同一个树,即是否使森林产生回路,如果

weixin_49561445的博客 2755

瑞芯微Android固件修改实战:从解包到root提权完整流程(附工具包)

本文详细解析了瑞芯微Android固件深度定制全流程,涵盖从固件包解包、系统镜像修改到植入root提权与分区调整的实战步骤。通过工具链操作与原理剖析,指导开发者安全实现系统精简、权限获取及存储扩容,最终完成固件重新打包与刷机验证,适用于追求设备完全控制权的技术爱好者。

ujm56789012的博客 699

最小生成树(Prim算法,Kruskal算法)

用Prim算法和Kruskal两种算法实现构建并输出最小生成树

m0_63223213的博客 7991

C# + NAudio:构建支持实时音频处理的语音聊天应用(含回声消除)

本文介绍了如何利用C#和NAudio库开发实时语音聊天应用,重点实现回声消除功能。首先概述了NAudio库在音频处理中的作用,包括音频录制、播放和实时处理能力。然后详细讲解了构建基础语音聊天应用的过程,包括麦克风录制和扬声器播放的实现。接着深入探讨了回声消除的原理和实现方法,提出通过比较麦克风输入和扬声器输出的音频信号来消除回声,并给出了核心代码示例。最后,文章还讨论了性能优化方向,如多线程处理和网络传输扩展。该方案为开发高质量实时语音应用提供了实用参考。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1013

车载ECU底软测试:方法与技术的深度解析

底软是运行在 ECU 硬件平台上的基础软件,它为上层应用程序提供了硬件驱动、操作系统服务、通信协议栈等功能。底软的主要功能包括:硬件驱动:负责与 ECU 的各种硬件外设进行通信和控制,如 GPIO、UART、SPI、CAN 等。操作系统服务:提供任务调度、内存管理、中断处理等功能,确保系统的实时性和稳定性。通信协议栈:实现 ECU 与其他 ECU 或外部设备之间的通信,如 CAN、LIN、FlexRay 等。诊断服务:负责对 ECU 的故障进行诊断和处理,并将故障信息存储在故障码存储器中。

天赐好车的博客 1430

最小生成树算法(Prim Kruskal)

最小生成树算法总览 最小生成树的定义及性质 Prim(普利姆)算法[朴素Prim算法 堆优化Prim算法] Prim算法求最小生成树[朴素Prim的代码实现 堆优化Prim的代码实现] Kruskal(克鲁斯卡尔)算法[Kruskal算法求最小生成树]

咸鱼势力登场 3万+

UE5 蓝图节点图文大全(300+蓝图,9万字+)

本文采用虚幻5.2.1版本,以图文的方式对蓝图节点进行介绍,包括蓝图节点的输入输出参数解释,并有中英文节点名称可参考。

一碗清深的博客 2万+

图解最小生成树问题:Kruskal算法和Prim算法

本文全面介绍了两类经典算法,用于解决无向图中的最小生成树(MST)问题。文章解释了最小生成树的概念,并详细对比分析了Kruskal和Prim两种算法的原理、特点及应用场景。文章重点以图文并茂的方式,通过示例演示了算法的执行过程,包括详细的步骤解析和权值图示。Kruskal算法侧重边的逐步加入,适用于稀疏图;Prim算法侧重点的逐步扩张,适用于稠密图。两者均采用贪心策略,在网络设计、电路布线等领域有着广泛的应用。

m0_74496615的博客 2698

2023年高教社杯全国大学生数学建模竞赛 E 题:《黄河水沙监测数据分析》真题解析与 MATLAB 解决方案

🏆 本文已收录于专栏:《滚雪球学数学建模(含历年真题)》,持续更新最新及历年数学建模竞赛资料,每篇内容力求做到“问题讲透、模型讲清、代码可用、论文可参考”,帮助你从零开始逐步建立完整的数学建模知识体系。

**My Coding Family** 904

GEE高阶应用——如何绘制2000-2022年土地利用变化轨迹时序图

土地利用变化是指在一定时间范围内,土地利用类型和结构发生的变化。时序变化是指这种变化随时间的推移而发生的序列变化。土地利用变化轨迹的时序变化具体介绍如下:首先,土地利用变化轨迹的时序变化体现在土地利用类型的演变上。在过去的几十年里,随着人口的增加、经济的发展和城市化的推进,土地利用类型发生了显著的变化。传统的农田逐渐减少,而城市、工业、交通、居住等用地的面积不断扩大。同时,随着环境保护意识的提高,生态保护用地、森林、湿地等绿色用地的面积也在增加。

此星光明博客 1114

数据结构C++——最小生成树之Prim算法和Kruskal算法

数据结构C++——最小生成树之Prim算法和Kruskal算法 文章目录数据结构C++——最小生成树之Prim算法和Kruskal算法一、最小生成树的基本概念二、最小生成树之Prim算法①Prim算法的实现原理②Prim算法中的Min函数的实现③Prim算法的代码实现④测试的完整代码三、最小生成树之Kruskal算法①Kruskal算法的实现原理②Krusal算法的代码实现③测试的完整代码四、总结 一、最小生成树的基本概念 最小生成树: 在一个连通网的所有生成树中,各边的代价之和最小的那棵生成树称为该连通网

qq_54162207的博客 8323

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

最小生成树—Kruskal算法和Prim算法

求图的最小生成树的两种算法Kruskal算法和Prim算法解析

终为nullptr 2279

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

【算法笔记】Kruskal/Prim算法——求解最小生成树问题

最小生成树问题:给定一张带权无向图G,求它的一棵生成树,使其中所有边权之和最小。本文将介绍针对这种问题的两种经典算法——Kruskal和Prim。

天生我材必有用,千金散尽还复来。 4946

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

最小生成树Kruskal、Prim算法C++

Kruskal算法和prim算法解决图的最小生成树问题,使用C++语言实现

Brant_zero的博客 1158

最小生成树——Prim算法与Kruskal算法

讲解图论中构造最小生成树的Prim算法思想,并通过C语言实现算法。

仅以此博客记录日常学习工作中所思所得,水平有限,难登大雅,万望海涵。 1804
上一篇: 有向图—拓扑排序,Kosaraju算法
下一篇: 最短路径算法—Dijkstra算法和BellmanFord算法
luoz_python
博客等级 码龄10年 57粉丝 47原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值