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

yizhihongxing

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封装一个控制台进度条插件​​​​​​​详情

    下面就给您讲解一下 “node封装一个控制台进度条插件”的攻略。 1.了解进度条插件相关知识 首先,我们需要了解一下进度条插件的相关知识。所谓进度条插件,就是在某个任务运行时,以一定频率输出当前的进度,用于直观的表示任务是否已完成或正在进行。一般情况下,进度条插件会在控制台中输出一行文本,其中包含百分比和进度条等可视化信息。 2.安装进度条插件 使用npm安…

    node js 2023年6月8日
    00
  • 使用nvm和nrm优化node.js工作流的方法

    以下是使用nvm和nrm优化node.js工作流的完整攻略。 为什么需要nvm和nrm 在进行Node.js开发的时候,经常需要切换不同版本的Node.js和使用不同的npm源,这时候就需要使用nvm和nrm。 nvm是Node.js的版本管理工具,可以让我们轻松地在同一个机器上切换不同版本的Node.js。nrm是NPM镜像源管理工具,可以让我们快速地切换…

    node js 2023年6月8日
    00
  • NodeJs实现简易WEB上传下载服务器

    下面我将详细讲解“NodeJs实现简易WEB上传下载服务器”的完整攻略。 简介 本攻略介绍如何使用Node.js实现一个简单的WEB上传下载服务器。 准备工作 在开始实现本题之前,需要确保你已经安装了Node.js和npm。 创建项目并添加依赖 首先,创建一个文件夹作为你的工作目录,进入该文件夹,打开命令行工具,输入以下命令: npm init 按照提示,完…

    node js 2023年6月8日
    00
  • 实例详解AngularJS实现无限级联动菜单

    实现无限级联动菜单的步骤 第一步:引入AngularJS 在HTML文件中引入AngularJS库,可以使用CDN或者下载本地文件。例如: <script src="https://cdn.bootcdn.net/ajax/libs/angular.js/1.8.2/angular.min.js"></script&gt…

    node js 2023年6月8日
    00
  • js仿微信抢红包功能

    让我为您讲解一下“js仿微信抢红包功能”的完整攻略吧。 环境准备 确定需要模拟的网页地址,推荐使用微信官网的微信红包页面。 安装浏览器插件 Tampermonkey,该插件能够注入自己编写的 JS 代码至指定网页中。 实现过程 监听红包页面加载完毕事件,获取页面中所有的红包。 遍历红包并判断其是否已被领取,如果未被领取则模拟点击,否则不做任何操作。 领取红包…

    node js 2023年6月8日
    00
  • node+express+ejs使用模版引擎做的一个示例demo

    下面是详细讲解“node+express+ejs使用模版引擎做的一个示例demo”的完整攻略。 什么是Node.js Node.js是一个基于Chrome V8 JavaScript引擎的开源、跨平台的JavaScript运行环境。它可以使JavaScript在服务器端运行,用于构建快速的网络应用程序。 什么是Express Express是一个基于Node…

    node js 2023年6月8日
    00
  • JavaScript内存管理与闭包实例详解

    JavaScript内存管理与闭包实例详解 什么是JavaScript内存管理? JavaScript在运行时使用动态内存分配。当它需要使用内存时,它会请求所需数量的内存,当它不再使用内存时,它会释放该内存。但是,JavaScript没有提供垃圾回收机制来自动释放不再使用的内存。相反,开发人员需要手动管理内存。这意味着从内存分配到内存释放都是由开发人员掌控的…

    node js 2023年6月8日
    00
  • JavaScript实现的图像模糊算法代码分享

    下面为您详细讲解“JavaScript实现的图像模糊算法代码分享”的完整攻略。 步骤一:获取图像数据 我们首先需要获取一个图片的像素点数据,可以使用<canvas>元素来实现。首先将图片绘制到canvas上,然后可以使用getImageData()方法来获取图像的像素点数据,该方法返回一个ImageData对象,可包含一个canvas对象上指定矩…

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