通过Java理解Kruskal算法

2023-11-17

今天,我将解析一段Java代码,该代码实现了Kruskal算法,用于在连通的无向图中找到最小生成树。

首先,我们来了解一些关键组件:

1. DisjointSet(不相交集):**

这是Kruskal算法中的辅助数据结构,用于管理不相交集的集合。

  • Find(查找):确定特定元素属于哪个集合,并返回该集合的代表成员。
  • Union(合并):将两个不同的集合合并为一个集合。

2. Kruskal:**

这个类包含实现Kruskal算法的方法。

  • worst_case(最坏情况):该方法演示如何使用预定义的边集合来利用算法。
  • Kruskal:该方法提供Kruskal算法的逻辑。

Kruskal算法的工作原理:

  1. 初始化:从每个顶点开始,构建一个由不相交的单节点树组成的森林。
  2. 排序:按照边的权重进行非递减排序。
  3. 添加边:对于每条边,按照非递减的顺序,如果边连接了两个不同的树,则将其添加到森林中,将两个树合并为一棵树。如果边连接了同一棵树的节点,则跳过它(以避免形成环)。
  4. 终止:算法在添加了(V-1)条边后结束,其中V是顶点的数量。
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

// DisjointSet 类用于管理不相交集的集合
class DisjointSet {
    private int[] parent; // 存储每个节点的父节点
    private int[] rank; // 存储每个节点的秩(树的高度)

    // 构造函数,初始化 DisjointSet
    public DisjointSet(int n) {
        parent = new int[n + 1]; // 考虑从1开始的节点索引
        rank = new int[n + 1];
        for (int i = 0; i <= n; i++) {
            parent[i] = i; // 每个节点的父节点初始化为自身
            rank[i] = 0; // 每个节点的秩初始化为0
        }
    }

    // 查找方法,返回节点 x 所在集合的代表元素
    public int find(int x) {
        if (parent[x] != x) {
            parent[x] = find(parent[x]); // 路径压缩
        }
        return parent[x];
    }

    // 合并方法,将 x 和 y 所在的集合合并,返回 true 如果合并成功,否则返回 false
    public boolean union(int x, int y) {
        int rootX = find(x);
        int rootY = find(y);

        if (rootX == rootY) {
            return false; // 已经在同一个集合中
        }

        // 将秩较低的树的根节点指向秩较高的树的根节点
        if (rank[rootX] < rank[rootY]) {
            parent[rootX] = rootY;
        } else if (rank[rootX] > rank[rootY]) {
            parent[rootY] = rootX;
        } else {
            parent[rootY] = rootX;
            rank[rootX]++;
        }

        return true;
    }
}

public class Kruskal {
    // 示例图的邻接矩阵表示
    int[][] example_1 = new int[][] { { 0, 1, 3, Integer.MAX_VALUE, Integer.MAX_VALUE },
            { 1, 0, 3, 6, Integer.MAX_VALUE },
            { 3, 3, 0, 4, 2 },
            { Integer.MAX_VALUE, 6, 4, 0, 5 },
            { Integer.MAX_VALUE, Integer.MAX_VALUE, 2, 5, 0 } };

    // worst_case 方法演示了如何使用预定义的边集合来利用 Kruskal 算法
    public void worst_case() {
        int n = 5; // 顶点数
        int m = 7; // 边数

        Set<Edge> E = new HashSet<>(); // 存储边的集合

        // 添加边到集合
        E.add(new Edge(1, 2, 1));
        E.add(new Edge(1, 3, 3));
        E.add(new Edge(2, 3, 3));
        E.add(new Edge(2, 4, 6));
        E.add(new Edge(3, 4, 4));
        E.add(new Edge(3, 5, 2));
        E.add(new Edge(4, 5, 5));

        // 将 Set 转换为 List
        List<Edge> edgeList = new ArrayList<>(E);

        // 对 List 进行排序
        edgeList.sort(Comparator.comparingInt(Edge::getWeight));

        // 创建一个不相交集
        DisjointSet disjointSet = new DisjointSet(n);

        // 创建一个列表来存储 MST 的边
        List<Edge> mst = new ArrayList<>();

        // 按排序顺序遍历所有边
        for (Edge edge : edgeList) {
            // 如果边不形成环,将其添加到 MST 中
            if (disjointSet.union(edge.getU(), edge.getV())) {
                mst.add(edge);
            }
        }

        // 显示 MST 中的边
        System.out.println("Minimum Spanning Tree: ");

        for (Edge edge : mst) {
            System.out.println("From: " + edge.getU() + " To: " + edge.getV() + " Weight: " + edge.getWeight());
        }
    }

    // kruskal 方法提供了 Kruskal 算法的逻辑
    public Set<Edge> kruskal(int n, int m, Set<Edge> E) {
        int i, j;

        Set<Edge> P = new HashSet<>();
        Set<Edge> Q = new HashSet<>();

        Edge e = new Edge(0, 0, 0);

        Set<Edge> F = new HashSet<>();

        // 当 F 的大小小于 (n - 1) 时,继续循环
        while (F.size() < (n - 1)) {
            // 将 E 中的边移动到 P 中
            for (i = 0; i < m; i++) {
                e = E.iterator().next();
                E.remove(e);
                P.add(e);
            }

            // 从 P 中选择一条边,如果它不连接同一个顶点,将其添加到 F 中
            for (i = 0; i < m; i++) {
                e = P.iterator().next();
                P.remove(e);
                if (e.getU() != e.getV()) {
                    F.add(e);
                    break;
                } else {
                    Q.add(e);
                }
            }

            // 将 Q 中的边移回 P 中
            for (i = 0; i < m; i++) {
                e = Q.iterator().next();
                Q.remove(e);
                P.add(e);
            }
        }

        return F;
    }
}

代码深入解析

Kruskal类中:

  1. worst_case方法:该方法首先初始化一组边,然后根据它们的权重对这些边进行排序。然后,代码遍历这些边,如果它们不形成环,则将它们添加到最小生成树中。
  2. Kruskal方法:这个方法看起来更复杂,有多个循环和集合PQF

然而,提供的方法并不遵循传统的Kruskal算法。相反,它展示了通过重复迭代边来构建最小生成树的另一种方法。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

通过Java理解Kruskal算法 的相关文章

  • 如何在日期选择器中设置不在当前月份的单元格的样式

    我目前正在为我的 JavaFX 应用程序制作注册表 问题是 当日期选择器中的单元格不在页面的月份上时 我想让该单元格变灰 让我们看看我当前的日期选择器 我的日期选择器 正如您所看到的 我希望下个月的日期 27 日 28 日 30 日以及 1
  • 热重载在docker中运行的java程序

    我开发了一个java程序 应该在docker中运行 然而 我在调试docker中运行的java程序时遇到了很多痛苦 我在网上搜索 一些教程提出了像 spring dev tools 这样的工具 因为我的java程序是基于spring boo
  • 如何将 Java 赋值表达式转换为 Kotlin

    java中的一些东西就像 int a 1 b 2 c 1 if a b c System out print true 现在它应该转换为 kotlin 就像 var a Int 1 var b Int 2 var c Int 1 if a
  • AES 加密 Java/plsql

    我需要在Java和plsql DBMS CRYPTO for Oracle 10g 上实现相同的加密 解密应用程序 两种实现都工作正常 但这里的问题是我对相同纯文本的加密得到了不同的输出 下面是用于加密 解密过程的代码 Java 和 PLS
  • 解决错误:日志已在具有多个实例的atomikos中使用

    我仅在使用atomikos的实时服务器上遇到问题 在我的本地服务器上它工作得很好 我在服务器上面临的问题是 init 中出错 日志已在使用中 完整的异常堆栈跟踪 java lang RuntimeException Log already
  • Java8无符号算术

    据广泛报道 Java 8 具有对无符号整数的库支持 然而 似乎没有文章解释如何使用它以及有多少可能 有些函数 例如 Integer CompareUnsigned 很容易找到 并且似乎可以实现人们所期望的功能 但是 我什至无法编写一个简单的
  • IntelliJ IDEA 创建的 JAR 文件无法运行

    我在 IntelliJ 中编写了一个跨越几个类的程序 当我在 IDE 中测试它时它运行良好 但是 每当我按照教程将项目制作成 jar 可执行文件时 它就不会运行 双击 out 文件夹中的文件时 该文件不会运行 并显示 无法启动 Java J
  • 使用 ANTLR 为 java 源代码生成抽象语法树

    如何使用 ANTLR 从 java src 代码生成 AST 有什么帮助吗 好的 步骤如下 前往ANTLR站点 http www antlr org 并下载最新版本 下载Java g和JavaTreeParser g文件来自here htt
  • HDFS:使用 Java / Scala API 移动多个文件

    我需要使用 Java Scala 程序移动 HDFS 中对应于给定正则表达式的多个文件 例如 我必须移动所有名称为 xml从文件夹a到文件夹b 使用 shell 命令我可以使用以下命令 bin hdfs dfs mv a xml b 我可以
  • 当分配给变量时,我可以以某种方式重用 Gremlin GraphTraversals 代码吗?

    我有看起来像这样的 GraphTraversals attrGroup GraphTraversal
  • Java 页面爬行和解析之 Crawler4j 与 Jsoup

    我想获取页面的内容并提取其中的特定部分 据我所知 此类任务至少有两种解决方案 爬虫4j https github com yasserg crawler4j and Jsoup http jsoup org 它们都能够检索页面的内容并提取其
  • 如何在jsp代码中导入java库?

    我有以下jsp代码 我想添加 java io 等库 我怎样才能做到这一点
  • 迁移到 java 17 后有关“每个进程的内存映射”和 JVM 崩溃的 GC 警告

    我们正在将 java 8 应用程序迁移到 java 17 并将 GC 从G1GC to ZGC 我们的应用程序作为容器运行 这两个基础映像之间的唯一区别是 java 的版本 例如对于 java 17 版本 FROM ubuntu 20 04
  • 检查 protobuf 消息 - 如何按名称获取字段值?

    我似乎无法找到一种方法来验证 protobuf 消息中字段的值 而无需显式调用其 getter 我看到周围的例子使用Descriptors FieldDescriptor实例到达消息映射内部 但它们要么基于迭代器 要么由字段号驱动 一旦我有
  • 尝试使用 Ruby Java Bridge (RJB) gem 时出现错误“无法创建 Java VM”

    我正在尝试实现 Ruby Java Bridge RJB gem 来与 JVM 通信 以便我可以运行 Open NLP gem 我在 Windows 8 上安装并运行了 Java 所有迹象 至少我所知道的 都表明 Java 已安装并可运行
  • org.jdesktop.application 包不存在

    几天以来我一直在构建一个 Java 桌面应用程序 一切都很顺利 但是今天 当我打开Netbeans并编译文件时 出现以下编译错误 Compiling 9 source files to C Documents and Settings Ad
  • 使用 SAX 进行 XML 解析 |如何处理特殊字符?

    我们有一个 JAVA 应用程序 可以从 SAP 系统中提取数据 解析数据并呈现给用户 使用 SAP JCo 连接器提取数据 最近我们抛出了一个异常 org xml sax SAXParseException 字符引用 是无效的 XML 字符
  • Android JNI C 简单追加函数

    我想制作一个简单的函数 返回两个字符串的值 基本上 java public native String getAppendedString String name c jstring Java com example hellojni He
  • com.jcraft.jsch.JSchException:身份验证失败

    当我从本地磁盘上传文件到远程服务器时 出现这样的异常 com jcraft jsch JSchException Auth fail at org apache tools ant taskdefs optional ssh Scp exe
  • 中断连接套接字

    我有一个 GUI 其中包含要连接的服务器列表 如果用户单击服务器 则会连接到该服务器 如果用户单击第二个服务器 它将断开第一个服务器的连接并连接到第二个服务器 每个新连接都在一个新线程中运行 以便程序可以执行其他任务 但是 如果用户在第一个

随机推荐

  • windows11如何安装docker desktop

    我们知道docker的安装一般我们是安装在linux系统上的 但是如果你的宿主机是windows 那么你还想装docker 那么就需要现在你的windows上装上虚拟机 虚拟机上装linux操作系统 然后在Linux操作系统上再去安装doc
  • BizTalk2010简介

    绝大多数现代业务流程都或多或少地依赖于其它软件 尽管其中部分流程仅由单个应用程序支持 但其他许多业务流程都依赖于不同的软件系统 在许多情况下 已使用不同的技术在不同时间 不同平台上创建了此软件 若要使这些业务程序实现自动化 则需要连接不同系
  • 大屏可视化关键技术

    大屏可视化的技术中涉及的范围会比较广 拆开来说诸如各种LED视频技术 互联网技术 智能技术 视觉设计技术等等这些技术 都是跟大屏可视化有着千丝万缕断不开的关系 但真正影响到大屏可视化关键技术却在于下面的3点上 大屏可视化关键技术 第1是大数
  • 系统及服务器巡检流程图,业务巡检系统的整体设计和数据流程

    这是学习笔记的第1789篇文章 近期也总结了几篇关于巡检的内容 很多同学也很期待 说业务巡检是一个新概念 想做成什么样子 或者说怎么样做起来更好一些 最近的几篇文章 在这个基础上 我自己也梳理了不少方面的内容 其实发起做这个事情 脑子里面已
  • 机器学习训练营LightGBM学习笔记

    学习知识点概要 1 LightGBM 2 LightGBM的实现 学习内容 1 LightGBM LightGBM可以看作是XGBoost的升级豪华版 在获得与XGBoost近似精度的同时 又提供了更快的训练速度与更少的内存消耗 其优缺点和
  • 在事情没有变得糟糕之前_这是我们没有的问题的糟糕解决方案

    在事情没有变得糟糕之前 最糟糕的代码是什么 不要说JavaScript 它会在你身上成长 不 也不是Perl 好的 所以Perl非常令人讨厌 最糟糕的代码 这是我们不需要的代码 紧接着是几乎有效的代码 然后是无效的代码 几乎可以正常工作的代
  • sim卡安全问题

    USIM 存储支持鉴权密钥K 是整个UMTS安全体系的核心 接受参数有 随机数 RAND 鉴权标志参数 AUTN 并计算生成消息鉴权码 XMAC 响应参数 RES 完整性保护密钥 IK 鉴权密钥 CK GSM的SIM卡仅是一种单应用卡 它仅
  • ora-12542 address in used

    这主要是由于 操作系统的 临时端口 不够用而引起的 一般系统的 临时端口为 1024 5000 这在多用户的环境下 3000多个oracle链接就用光了 由于每个链接断开以后 还要有一个等待时间 例如在 windows 系统中 这个时间是
  • 比亚迪后续车都会搭在鸿蒙系统吗_华为手机也能当车钥匙,搭载鸿蒙系统,5G款比亚迪赶超特斯拉?...

    一直以来 互联网公司在造车这事儿上都被认为不太靠谱 虽然这点可以让下周回国贾跃亭和他的ff91背下锅 但依然改变不了我们造的车还不是那个 味 有时候我们自己也会疑问 为什么我们为啥没有自己的特斯拉 不过这件事情目前来看 似乎已经不是什么难题
  • windows下C盘文件夹管理员权限设置

    我们有时会将一些软件安装在C盘 却发现有时程序对C盘文件增删改操作失败 然后自己手动去执行时也经常弹出 你需要提供管理员权限才能进删除此文件 之类 这很烦 网上有些说法是开启Administrator用户 但是我这种有点洁癖的不喜欢增加一个
  • java b 类型_什么类型的Java类型是“[B”?

    我试图通过Java代码 Hibernate 从MySQL DB获取MD5加密传递 但我不能得到字符串或任何合理的Java类型 我唯一得到的是这个无益的信息 java lang ClassCastException B无法转换为com mys
  • 封装与检测技术

    环氧树脂 环氧树脂是一种高分子聚合物 分子式为 C 11 H 12 O 3
  • 复杂的密码有多重要?实操暴力破解wifi密码......

    暴力破解就是穷举法 将密码字典中每一个密码依次去与握手包中的密码进行匹配 直到匹配成功 注意 私自破解他人WiFi属于违法行为 本教程仅供学习与参考 破解工具 破解工具 kali linux系统 本教程使用的装在物理机的linux系统 虚拟
  • postgresql 中输入逃逸字符\n\r\b\t

    例如 1 建表 create table test a1 text a2 varchar 100 a3 char 200 2 插入数据 使用关键字 E insert into test a1 a2 a3 values E aaa n aaa
  • linux ssh服务是否已经启动?

    linux ssh服务是否已经启动 突然想到 ubuntu貌似默认是不会安装ssh server的 会默认安装ssh client 恍然大悟 是不是因为这个原因 于是查看发现 果然没有安装 下面进行安装openssh server sudo
  • Linux系统常用基本命令总结

    Linux基本命令 Linux的简介 Linux的厂商 Linux的目录结构 基于虚拟机的环境搭建 常用命令与示例 一 文件基本操作命令 1 ls命令 2 pwd命令 3 mkdir命令 4 cd命令 5 touch命令 6 cp命令 7
  • ubuntu13.10 64位系统下载Android源码

    参考http source android com source downloading html进行下载 下载过程中出现的问题参考http blog 163 com aravarcv 126 blog static 12384272820
  • (超级详细)如何在Mac OS上的VScode中配置OpenGL环境并编译

    文章目录 安装环境 下载GLAD与GLFW 一 下载GLAD 二 下载GLFW 项目结构配置 测试程序与项目的编译 测试可执行文件HelloGL 安装环境 机器 macbook air 芯片 M1芯片 arm64 macOS macOS V
  • SHA-256算法实现过程

    整理一下SHA 256的实现步骤 1 定义8个32位常量 h0 0x6a09e667 h1 0xbb67ae85 h2 0x3c6ef372 h3 0xa54ff53a h4 0x510e527f h5 0x9b05688c h6 0x1f
  • 通过Java理解Kruskal算法

    今天 我将解析一段Java代码 该代码实现了Kruskal算法 用于在连通的无向图中找到最小生成树 首先 我们来了解一些关键组件 1 DisjointSet 不相交集 这是Kruskal算法中的辅助数据结构 用于管理不相交集的集合 Find