Prim算法和Kruskal算法到底哪个好?

这篇具有很好参考价值的文章主要介绍了Prim算法和Kruskal算法到底哪个好?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Prim和Kruskal有啥区别?到底哪个好?

今天做了一道最小生成树的题,发现了一点猫腻!
题目在这里 : 《修路问题1》



先说结论

Prim算法Kruskal算法 都是从连通图中找出 最小生成树 的经典算法~

从策略上来说,Prim算法是直接查找,多次寻找邻边的权重最小值,而 Kruskal是需要先对权重排序后查找的

所以说,Kruskal在算法效率上是比Prim快的 ,因为Kruskal只需一次对权重的排序就能找到最小生成树,而Prim算法需要多次对邻边排序才能找到~

Prim

Prim算法是一种产生最小生成树的算法。该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vojtěch Jarník)发现;
并在1957年由美国计算机科学家罗伯特·普里姆(英语:Robert C. Prim)独立发现;1959年,艾兹格·迪科斯彻再次发现了该算法。

Prim算法从任意一个顶点开始每次选择一个与当前顶点集最近的一个顶点,并将两顶点之间的边加入到树中。Prim算法在找当前最近顶点时使用到了贪婪算法。朴素版时间复杂度为:O(n²) ,堆优化过后的prim时间复杂度为O(mlogn)

算法描述:

  1. 在一个加权连通图中,顶点集合V,边集合为E
  2. 任意选出一个点作为初始顶点,标记为visit,计算所有与之相连接的点的距离,选择距离最短的,标记visit.
  3. 重复以下操作,直到所有点都被标记为visit:
    在剩下的点中,计算与已标记visit点距离最小的点,标记visit,证明加入了最小生成树。

prim算法和kruskal算法的区别,数据结构与算法,算法,图论,数据结构

Kruskal

Kruskal是另一个计算最小生成树的算法,其算法原理如下。首先,将每个顶点放入其自身的数据集合中。然后,按照权值的升序来选择边。当选择每条边时,判断定义边的顶点是否在不同的数据集中。如果是,将此边插入最小生成树的集合中,同时,将集合中包含每个顶点的联合体取出,如果不是,就移动到下一条边。重复这个过程直到所有的边都探查过。

prim算法和kruskal算法的区别,数据结构与算法,算法,图论,数据结构
prim算法和kruskal算法的区别,数据结构与算法,算法,图论,数据结构

第1步:将边<E,F>加入R中。
边<E,F>的权值最小,因此将它加入到最小生成树结果R中。
第2步:将边<C,D>加入R中。
上一步操作之后,边<C,D>的权值最小,因此将它加入到最小生成树结果R中。
第3步:将边<D,E>加入R中。
上一步操作之后,边<D,E>的权值最小,因此将它加入到最小生成树结果R中。
第4步:将边<B,F>加入R中。
上一步操作之后,边<C,E>的权值最小,但<C,E>会和已有的边构成回路;因此,跳过边<C,E>。同理,跳过边<C,F>。将边<B,F>加入到最小生成树结果R中。
第5步:将边<E,G>加入R中。
上一步操作之后,边<E,G>的权值最小,因此将它加入到最小生成树结果R中。
第6步:将边<A,B>加入R中。
上一步操作之后,边<F,G>的权值最小,但<F,G>会和已有的边构成回路;因此,跳过边<F,G>。同理,跳过边<B,C>。将边<A,B>加入到最小生成树结果R中。

修路问题1——题目描述

prim算法和kruskal算法的区别,数据结构与算法,算法,图论,数据结构
prim算法和kruskal算法的区别,数据结构与算法,算法,图论,数据结构
输入示例:

5 6
1 2 2
1 3 7
1 4 6
2 3 1
3 4 3
3 5 2

输出

8

Kruskal(过了100%)

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;

/**
 * Created with IntelliJ IDEA.
 *
 * @Auther: LiangXinRui
 * @Date: 2023/3/3 9:07
 * @Description: Kruskal算法在找最小生成树结点之前,需要对权重从小到大进行排序。
 * 将排序好的权重边依次加入到最小生成树中(如果加入时产生回路就跳过这条边,加入下一条边),
 * 当所有的结点都加入到最小生成树中后,就找到了这个连通图的最小生成树~
 */
public class demo83_kruskal_修建公路 {
    static final int N = 300005;
    static int n,m,count;
    static long sum;
    static Edge[] edges = new Edge[N];
    static int[] pre = new int[N];
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

    static int find(int v) {
        if (v != pre[v]) {
            pre[v] = find(pre[v]);
        }
        return pre[v];
    }

    public static void main(String[] args) throws Exception {
        String[] s = br.readLine().split(" ");
        n = Integer.parseInt(s[0]);
        m = Integer.parseInt(s[1]);
        for (int i = 1; i <= n; i++) {
            pre[i] = i;
        }
        for (int i = 0; i < m; i++) {
            String[] s1 = br.readLine().split(" ");
            int a, b, c;
            a = Integer.parseInt(s1[0]);
            b = Integer.parseInt(s1[1]);
            c = Integer.parseInt(s1[2]);
            edges[i] = new Edge(a, b, c);
        }
        Arrays.sort(edges, 0, m);

        for (int i = 0; i < m; i++) {
            int a = edges[i].a;
            int b = edges[i].b;
            int w = edges[i].w;
            a = find(a);
            b = find(b);
            if (a != b) {//这里不能写成 if (find(a) != find(b))
                pre[a] = b;
                sum += w;
                count++;
            }
        }
        if (count == n - 1) {
            System.out.println(sum);
        } else {
            System.out.println(-1);
        }

    }

    static class Edge implements Comparable<Edge> {
        int a;
        int b;
        int w;

        Edge(int a, int b, int w) {
            this.a = a;
            this.b = b;
            this.w = w;
        }

        public int compareTo(Edge e) {
            return w - e.w;
        }
    }
}



堆优化的prim(过了60%,有可能哪儿写错了?)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

/**
 * @Author: LiangXinRui
 * @Date: 2023/03/02/20:16
 * @Description:
 */

public class demo83_prim_堆优化 {
    static int[] head, next, ends, pre;
    static int n, m, num, total, begin;
    static double sum;
    static double[] weights, dis;
    static boolean[] vis;
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

    static class pair {
        double first;//记录 边权
        int second;//记录 下一个结点

        public pair() {
        }

        public pair(double first, int second) {
            this.first = first;
            this.second = second;
        }
    }

    //自定义比较类,升序排列
    static Comparator<pair> comparator = (o1, o2) -> o1.first - o2.first > 0 ? 1 : 0;
    
    static Queue<pair> queue = new PriorityQueue<>(comparator);

    static void add(int start, int end, int weight) {
        ends[total] = end;
        weights[total] = weight;
        next[total] = head[start];
        head[start] = total;
        total++;
    }

    static void prim() {
        queue.offer(new pair(weights[0], ends[0]));
        vis[begin] = true;
        while (!queue.isEmpty() && num < n) {
            double len = queue.peek().first;
            int to = queue.peek().second;
            queue.poll();
            if (!vis[to]) {
                sum += len;
                num++;// 找到一条边
                vis[to] = true;// 标记一下,表示我这条边已经用过
                for (int i = head[to]; i != -1; i = next[i]) {
                    if (weights[i] < dis[ends[i]]) {// 如果当前边权小,更新
                        dis[ends[i]] = weights[i];
                        queue.offer(new pair(weights[i], ends[i]));// 把新的边权和结点加入队列
                    }
                }
            }
        }
    }

    public static void main(String[] args) throws IOException {
        String[] firstStr = br.readLine().split(" ");
        n = Integer.parseInt(firstStr[0]);
        m = Integer.parseInt(firstStr[1]);
        dis = new double[n + 1];
        head = new int[2 * m + 1];//表示以 i 为起点的最后一条边的编号
        next = new int[2 * m + 1];//存储与当前边起点相同的上一条边的编号
        ends = new int[2 * m + 1];//存储边的终点
        weights = new double[2 * m + 1];//存储边的权值
        vis = new boolean[2 * m + 1];
        Arrays.fill(head, -1);//初始化
        for (int i = 1; i <= n; i++) {
            dis[i] = Double.MAX_VALUE / 2;
        }
        for (int i = 0; i < m; i++) {
            String[] secondStr = br.readLine().split(" ");
            int start = Integer.parseInt(secondStr[0]);
            if (i == 0) begin = start;
            int end = Integer.parseInt(secondStr[1]);
            int weight = Integer.parseInt(secondStr[2]);
            add(start, end, weight);
            add(end, start, weight);
        }
        prim();
        if (n - 1 == num) {
            System.out.printf("%.0f", sum);
        } else {
            System.out.println("-1");
        }
    }

}


总结

遇到困难时首先想到的不应该是退缩,而是探索!

文章粗浅,希望对大家有帮助!

参考博客:
【最小生成树】Prim算法和Kruskal算法的区别对比
Prim算法(java)
克鲁斯卡尔算法(Kruskal)详解文章来源地址https://www.toymoban.com/news/detail-754889.html

到了这里,关于Prim算法和Kruskal算法到底哪个好?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 实验13 prim算法和kruskal算法

    🔑一个神奇的哔哩哔哩讲解链接 🔑笔记补充——第十七章:贪婪算法(思想同,但应用上和伪代码略有差别) 使用prim算法实现最小生成树 输入 第一行两个整数n,e。n ( 1 ≤ n ≤ 200000 1 leq n leq 200000 1 ≤ n ≤ 200000 ) 代表图中点的个数,e ( 0 ≤ m ≤ 500000 0 leq m leq 500000 0 ≤

    2024年02月04日
    浏览(39)
  • 最小生成树—Kruskal算法和Prim算法

    连通图:在无向图中,若从顶点v1到顶点v2有路径,则称顶点v1与顶点v2是连通的。如果图中任 意一对顶点都是连通的,则称此图为连通图。 生成树:一个连通图的最小连通子图称作该图的生成树。有n个顶点的连通图的生成树有n个顶点 和n-1条边。 最小生成树:构成生成树的

    2024年02月05日
    浏览(47)
  • 最小生成树(Prim算法与Kruskal算法)

    一个连通图的生成树是一个极小的连通子图,它含有图中全部的n个顶点,但只有足以构成一棵树的n-1条边。我们把构造连通网的最小代价生成树称为最小生成树。 例如下图中①、②、③都是左侧图的生成树,但③是构造连通网的最小代价,所以③是该图的最小生成树。 P

    2024年02月05日
    浏览(58)
  • 最小(代价)生成树—Prim算法与Kruskal算法

    目录  一、最小生成树的特点 二、最小生成树算法  ① Prim(普里姆)算法 ②Kruskal(克鲁斯卡尔)算法  ③Prim算法与Kruskal算法对比 最小生成树是带权连通图G=(V,E)的生成树中边的权值之和最小的那棵生成树。它具有以下特点: 图G中各边权值互不相等时有唯一的最小生成树。图

    2024年02月01日
    浏览(38)
  • 图论13-最小生成树-Kruskal算法+Prim算法

    基本思想:按照权值从小到大的顺序选择 n-1 条边,并保证这 n-1 条边不构成回路 具体做法:首先构造一个只含 n 个顶点的森林,然后依权值从小到大从连通网中选择边加入到森林中,并使森林中 不产生 回路,直至森林变成一棵树为止。 2.2.1 如果图不联通,直接返回空,该

    2024年02月01日
    浏览(50)
  • 最小生成树Kruskal、Prim算法C++

    连通图: 在无向图中,若从顶点v1到顶点v2有路径,则称顶点v1和顶点v2是连通的。如果图中任意一对顶点都是连通的,则称此图为连通图。 生成树: 一个连通图的最小连通子图称作为图的生成树。有 n个顶点 的连通图的生成树有 n个顶点和 n-1 条边。 最小生成树: 最小生活

    2024年02月10日
    浏览(41)
  • 【最小生成树】一文学懂prim、kruskal算法

    博主简介: 努力学习的大一在校计算机专业学生,热爱学习和创作。目前在学习和分享:算法、数据结构、Java等相关知识。 博主主页: @是瑶瑶子啦 所属专栏: 算法 ;该专栏专注于蓝桥杯和ACM等算法竞赛🔥 近期目标: 写好专栏的每一篇文章 首先,我们要了解什么是最小生

    2023年04月25日
    浏览(33)
  • 用prim和kruskal算法求最小生成树问题

    题目 http://ybt.ssoier.cn:8088/problem_show.php?pid=1350 信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn) http://ybt.ssoier.cn:8088/problem_show.php?pid=1391 相当于一个图中求最小生成树的问题 prim解决 kruskal解法 信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn) http://ybt.ssoier.cn:8088/problem_show.ph

    2024年02月09日
    浏览(39)
  • C语言实现最小生成树算法:Prim和Kruskal

    以下是使用C语言实现Prim算法生成最小生成树的代码: 注释如下: #include stdio.h 和 `#include #define V 5 定义了图中顶点的个数为5。 int minDistance(int dist[], int visited[]) 函数用于找到顶点集合中未访问的顶点中距离最小的顶点。输入参数 dist 用于存储顶点到最小生成树的距离,输入

    2024年02月03日
    浏览(43)
  • 第二十一章 Prim算法与Kruskal算法(通俗证明与详细讲解)

    我们先解释一下什么是最小生成树。 这个概念是基于图的,如果说存在一条路线串通起来了所有的点,那么这条路线就叫做生成树。而在这些路线中最短的那一条就叫做最小生成树。 如上图所示,图中的红色路线就是一个生成树,假设这条红色路线是众多生成树路线中最小

    2024年02月11日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包