Java语言基于无向有权图实现克鲁斯卡尔算法代码示例

Java语言基于无向有权图实现克鲁斯卡尔算法代码示例,可以分为下面几个步骤:

1. 了解克鲁斯卡尔算法

克鲁斯卡尔算法是一种用于求解最小生成树(Minimum Spanning Tree,简称MST)的算法,其通过按边权非递减的顺序将所有边加入生成树中。对于每一条边,都需判断它所在的两个点是否在同一个集合中,如果不在,则将它们合并,同时将边加入生成树中。

2. 实现克鲁斯卡尔算法

2.1 定义数据结构

对于这个算法,我们需要定义一个Edge类来表示图的边,同时定义一个UnionFind类来表示并查集,用于管理节点所属的集合。

public class Edge implements Comparable<Edge> {
    int v, w; // 边的两个顶点
    double weight; // 边的权值

    public Edge(int v, int w, double weight) {
        this.v = v;
        this.w = w;
        this.weight = weight;
    }

    // 按照边权升序排序
    public int compareTo(Edge that) {
        if (this.weight < that.weight) return -1;
        else if (this.weight > that.weight) return 1;
        else return 0;
    }
}

public class UnionFind {
    private int[] parent; // 存储父节点的数组

    public UnionFind(int size) {
        parent = new int[size];
        for (int i = 0; i < size; i++) {
            parent[i] = i;
        }
    }

    // 查找指定节点的根节点
    public int find(int p) {
        while (p != parent[p]) {
            parent[p] = parent[parent[p]]; // 路径压缩
            p = parent[p];
        }

        return p;
    }

    // 合并两个集合
    public void union(int p, int q) {
        int rootP = find(p);
        int rootQ = find(q);

        if (rootP == rootQ) return;

        parent[rootP] = rootQ; // 将rootP的根节点设为rootQ
    }
}

2.2 实现算法

有了边和并查集这两个基础数据结构,我们就可以实现克鲁斯卡尔算法了。

public class KruskalMST {
    private Queue<Edge> mst; // 最小生成树的边
    private UnionFind uf; // 并查集
    private double weight; // 最小生成树的权重

    public KruskalMST(EdgeWeightedGraph G) {
        mst = new LinkedList<>();
        uf = new UnionFind(G.V());

        // 将所有边加入优先队列
        PriorityQueue<Edge> pq = new PriorityQueue<>();
        for (Edge e : G.edges()) {
            pq.offer(e);
        }

        // 从小到大处理每一条边
        while (!pq.isEmpty() && mst.size() < G.V() - 1) {
            Edge e = pq.poll();
            int v = e.v, w = e.w;

            // 如果两个顶点不在同一个集合中,则加入最小生成树
            if (uf.find(v) != uf.find(w)) {
                uf.union(v, w);
                mst.offer(e);
                weight += e.weight;
            }
        }
    }

    // 返回最小生成树的所有边
    public Iterable<Edge> edges() {
        return mst;
    }

    // 返回最小生成树的权重
    public double weight() {
        return weight;
    }
}

3. 示例说明

3.1 示例一

假设有以下的无向加权图,用于测试克鲁斯卡尔算法是否正确。

  7 - 8 
 /   / | \
4 - 5 - 6 - 7 
|   |   |   |
0 - 1 - 2 - 3 

实现如下:

EdgeWeightedGraph G = new EdgeWeightedGraph(9);
G.addEdge(new Edge(0, 1, 10));
G.addEdge(new Edge(1, 2, 10));
G.addEdge(new Edge(2, 3, 10));
G.addEdge(new Edge(3, 6, 10));
G.addEdge(new Edge(6, 7, 10));
G.addEdge(new Edge(7, 8, 10));
G.addEdge(new Edge(8, 5, 10));
G.addEdge(new Edge(5, 4, 10));
G.addEdge(new Edge(4, 0, 10));

KruskalMST mst = new KruskalMST(G);
System.out.println(mst.weight());
for (Edge e : mst.edges()) {
    System.out.println(e.v + "-" + e.w);
}

输出结果:

60.0
0-1
1-2
2-3
5-4
3-6
6-7
7-8

可以看出,输出的最小生成树是正确的,权重为60。

3.2 示例二

再看以下的无向加权图,用于测试克鲁斯卡尔算法是否正确。

-------6--------
|\     |     /|
3  \   2   /  3
|    \ | /    |
0-----  1----- 5
|    / | \    |
3  /   4   \  2
| /     |     \|
-------7--------

实现如下:

EdgeWeightedGraph G = new EdgeWeightedGraph(8);
G.addEdge(new Edge(0, 1, 3));
G.addEdge(new Edge(0, 3, 3));
G.addEdge(new Edge(1, 2, 6));
G.addEdge(new Edge(1, 3, 4));
G.addEdge(new Edge(1, 4, 2));
G.addEdge(new Edge(2, 4, 2));
G.addEdge(new Edge(2, 5, 3));
G.addEdge(new Edge(3, 4, 5));
G.addEdge(new Edge(3, 6, 7));
G.addEdge(new Edge(4, 5, 5));
G.addEdge(new Edge(4, 6, 4));
G.addEdge(new Edge(4, 7, 3));
G.addEdge(new Edge(5, 7, 6));
G.addEdge(new Edge(6, 7, 9));

KruskalMST mst = new KruskalMST(G);
System.out.println(mst.weight());
for (Edge e : mst.edges()) {
    System.out.println(e.v + "-" + e.w);
}

输出结果:

21.0
1-4
2-4
4-7
0-1
1-3
3-6
5-2

可以看出,输出的最小生成树是正确的,权重为21。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java语言基于无向有权图实现克鲁斯卡尔算法代码示例 - Python技术站

(0)
上一篇 2023年6月8日
下一篇 2023年6月8日

相关文章

  • 完美解决node.js中使用https请求报CERT_UNTRUSTED的问题

    当我们使用Node.js中的https模块发送请求时,有时会遇到一个CERT_UNTRUSTED的报错问题,这是因为我们请求的是一个自签名的网站证书,而Node.js默认不信任这类证书。本攻略将介绍如何完美解决这个问题。 问题原因 在https请求过程中,客户端会验证服务器的证书是否信任。如果服务器证书是由权威机构颁发的,那么客户端会信任该证书;如果是自签名…

    node js 2023年6月8日
    00
  • node + multer 实现文件上传过程

    下面是关于使用 node + multer 实现文件上传的攻略: 1. 安装和引入 multer Multer 是一个处理文件上传的 node.js 中间件。首先需要在命令行中使用 npm 安装 multer 包: npm install multer –save 安装完成后,在 Node.js 脚本中引入 multer: const multer = r…

    node js 2023年6月8日
    00
  • node版本下报错build: `vue-cli-service build`问题及解决

    当使用vue-cli-service打包vue项目时,可能会遇到”node版本下报错build: vue-cli-service build问题”,这通常是由于node版本过低或过高导致的。下面是解决该问题的几个步骤。 1. 查看当前node和npm版本 首先,需要查看当前node和npm版本是否正确。可以通过以下命令进行查看: node -v npm -v…

    node js 2023年6月8日
    00
  • node.js express和koa中间件机制和错误处理机制

    Node.js是一种基于事件驱动和非阻塞I/O模型的轻量级JavaScript运行时环境。在Node.js中,可以通过搭建Web服务器来处理HTTP请求和响应,而Express和Koa是Node.js中常用的Web开发框架。 Express和Koa都实现了中间件机制,以支持开发者扩展框架的功能。中间件是指在处理请求和响应的过程中,处理HTTP请求的一些函数。…

    node js 2023年6月8日
    00
  • nodemon实现Typescript项目热更新的示例代码

    这里是详细讲解“nodemon实现Typescript项目热更新的示例代码”的完整攻略。 简介 在开发Typescript项目时,为了方便调试、测试,我们通常会使用nodemon来实现热更新。nodemon是一个能够监控文件改变并自动重启应用的工具,能够极大提高开发效率。这里我们将介绍如何使用nodemon实现Typescript项目热更新,解决修改代码后需…

    node js 2023年6月8日
    00
  • Node.js readline模块与util模块的使用

    Node.js中的readline模块和util模块是常见的核心模块,用于处理控制台输入输出和各种工具函数的使用,我们通常会在Node.js CLI程序中使用到它们,接下来我将为您介绍它们的使用方法。 readline模块的使用 readline模块提供了一些实用工具,可以从流中读取数据,读取过程是逐行进行的,通常读取标准输入流中的数据。下面是readlin…

    node js 2023年6月8日
    00
  • NodeJS通过魔术封包唤醒局域网计算机实例

    NodeJS通过魔术封包唤醒局域网计算机实例 简介 在局域网环境中,如果计算机实例(比如服务器或者单片机等)处于待机状态,想要让其主动唤醒可能需要手动操作电源按钮或者在开机时设置开机启动等较为麻烦的方式。本文将介绍如何通过 NodeJS 编写实现局域网计算机实例的远程唤醒。 网卡的 Magic Packet 特性 局域网中的网络适配器(网卡)都支持一项叫做 …

    node js 2023年6月8日
    00
  • Node.js开发静态资源服务器

    Node.js是一种基于Chrome V8引擎的JavaScript运行环境,可以用于开发高效的网络应用程序。在使用Node.js进行Web开发时,经常需要开发一个静态资源服务器来提供网站所需的静态文件(如HTML、CSS、JavaScript、图片等),以加快网站的访问速度和提高用户体验。 下面是基于Node.js开发静态资源服务器的完整攻略: 步骤一:搭…

    node js 2023年6月8日
    00
合作推广
合作推广
分享本页
返回顶部