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 readline 逐行读取、写入文件内容的示例

    Node.js 是一款基于 Chrome V8 引擎的 JavaScript 运行时,它提供了许多强大的 API,包括文件系统 API 和行读写 API,使得我们可以轻松地对文件进行读写和处理。 本文将为大家讲解如何使用 Node.js 的 readline API 对文件进行逐行读取和写入。具体步骤如下: 步骤一:引入 readline 和 fs 模块 首…

    node js 2023年6月8日
    00
  • NodeJS学习笔记之Connect中间件模块(二)

    NodeJS是目前最流行的服务器端JavaScript运行环境,其生态系统非常丰富,其中有一个重要的模块就是中间件(Connect Middleware)模块,它为Express和Koa等框架提供了基础设施。本文是“NodeJS学习笔记之Connect中间件模块(二)”,我将为大家详细讲解Connect模块的使用方法,让大家能够全面了解Connect模块的各…

    node js 2023年6月8日
    00
  • node.js使用net模块创建服务器和客户端示例【基于TCP协议】

    下面是详细讲解“node.js使用net模块创建服务器和客户端示例【基于TCP协议】”的完整攻略: 一、net模块简介 Node.js中的net模块提供了基于TCP或IPC(进程间通信)协议的网络通信功能,包括创建服务器和客户端等功能。在这里主要介绍基于TCP协议的创建服务器和客户端。 二、创建TCP服务器 要创建一个TCP服务器,需要调用net模块的cre…

    node js 2023年6月8日
    00
  • Node.js中的异步生成器与异步迭代详解

    Node.js中的异步生成器与异步迭代详解 异步迭代 异步迭代可以理解为一种异步操作处理流程,我们通过一个example框架来讲解其中的机制。 假设有这样一种场景,我们需要上传多张图片到远端服务器,并在所有的图片上传完成之后返回一个数组,数组中的每个元素为每一张图片上传成功后返回的结果。我们可以通过以下代码实现: async function uploadP…

    node js 2023年6月8日
    00
  • 详解redis在nodejs中的应用

    详解Redis在Node.js中的应用 简介 Redis是一个开源的、基于内存的key-value存储系统,数据存在内存中,因此读写速度快。Redis具有持久化和多种数据结构的支持,同时也是分布式系统下的良好选择。Node.js是一个充分利用事件驱动、非阻塞I/O的JavaScript运行时。结合Redis和Node.js,能够发挥它们的协同作用。 本文将着…

    node js 2023年6月8日
    00
  • NodeJS实现图片上传代码(Express)

    针对NodeJS实现图片上传代码(Express),我为你准备了完整的攻略,包括以下内容: 一、安装依赖 在开始之前,需要先确保你已经安装了NodeJS和NPM,如果没有,请先自行进行安装。然后在你的项目目录下执行以下命令安装必要的依赖: npm install express multer path –save 其中,multer是一个Node.js中间…

    node js 2023年6月8日
    00
  • 使用ThinkJs搭建微信中控服务的实现方法

    使用ThinkJs搭建微信中控服务的实现方法 ThinkJs是一个快速、简单而又强大的Node.js框架,使用它可以很快地搭建Web应用。本攻略将介绍如何使用ThinkJs来搭建微信中控服务,包括对接微信公众号服务器、处理微信公众号消息等。 创建项目 首先,我们需要安装ThinkJs,可以通过npm来安装: npm install -g think-cli …

    node js 2023年6月8日
    00
  • Node.js微信 access_token ( jsapi_ticket ) 存取与刷新的示例

    针对Node.js微信 access_token (jsapi_ticket) 存取与刷新的示例,我们可以按照以下步骤进行攻略: 第一步:获取access_token和jsapi_ticket 我们可以通过以下方式获取微信公众平台的access_token和jsapi_ticket: 获取access_token const request = requir…

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