Java实现并查集

Java实现并查集喝杯 82 年的 Java 压压惊这次需要介绍的就是并查集并查集的简单应用就是连通图 网络通信连接等等总之很重要那么先说一下这次的算法是 1 union find 简单并查集 2 quick union 优化的并查集 3 加权值 quick union 处理了 2 的最坏情况 4 路径压缩加权值 quick union 如果只是想要一下算法 你可以直接跳到最后看第 4 个算法接下来 我

喝杯82年的Java压压惊


这次需要介绍的就是并查集


那么先说一下 这次的算法是

1. union-find (简单并查集)

2.quick-union (优化的并查集)

3.加权值quick-union(处理了2的最坏情况)

4.路径压缩加权值quick-union

如果只是想要一下算法,你可以直接跳到最后看第4个算法



union-find

故事大概就讲完了 很好理解吧. 其实算法也不难

让我们先看一下 API

加粗样式

public class UnionFind { private int[] id; 存储这几伙强盗的逻辑关系 数组下标i代表第i伙强盗 值代表 他老大是谁 private int count; 表示一共有几个强盗团伙 public UnionFind(int N) 做初始化操作 N 代表一开始有几伙强盗 public int getCount() 获取强盗团伙的数量 public boolean connected(int p, int q) 判断 p 和 q 这两伙强盗 是不是一家的 public int find(int p) 找到第p伙强盗的老大 public void union(int p, int q) 联合两伙强盗 } 

好了让我们一个一个方法来看 首先看构造函数

 public UnionFind(int N) { count = N; id = new int[N]; for(int i = 0; i < N; i++) id[i] = i; } 
public int getCount() { return count; } 

这个方法就不用介绍了吧?

 public int find(int p) { return id[p]; } 

这个方法返回第P伙强盗的老大 id[p] 中存的值就是老大的下标

public boolean connected(int p, int q) { return find(p) == find(q); } 

看看 两个的老大是不是同一个 也很简单把?

接下来就是最关键的一个方法了

联合 其实也不难

public void union(int p, int q){ int pRoot = find(p); int qRoot = find(q); if(pRoot == qRoot) return; for(int i = 0; i < id.length; i++) if(id[i] == pRoot) id[i] = qRoot; count--; } 

完整代码

public class UnionFind { private int[] id; private int count; public UnionFind(int N) { count = N; id = new int[N]; for(int i = 0; i < N; i++) id[i] = i; } public int getCount() { return count; } public boolean connected(int p, int q) { return find(p) == find(q); } public int find(int p) { return id[p]; } public void union(int p, int q){ int pRoot = find(p); int qRoot = find(q); if(pRoot == qRoot) return; for(int i = 0; i < id.length; i++) if(id[i] == pRoot) id[i] = qRoot; count--; } } 

好了 让我们分析一下时间复杂度


通过上面的问题 我们需要优化一下算法

quick-union

其他方法不用变 只需要 修改 find() 和 union的两个方法就可以 首先看一下 find()

public int find(int p) { while(p != id[p]) p = id[p]; return p; } 

所以先看一下 union()方法

public void union(int p, int q){ int pRoot = find(p); int qRoot = find(q); if(pRoot == qRoot) return; id[pRoot] = qRoot; count--; } 

在这里插入图片描述

这里3干掉了5 就给3和5 连一条线 并且 ip[5] = 3;

在这里插入图片描述

完整代码

public class QuickUnion { private int[] id; private int count; publicQuickUnion(int N) { count = N; id = new int[N]; for(int i = 0; i < N; i++) id[i] = i; } public int getCount() { return count; } public boolean connected(int p, int q) { return find(p) == find(q); } public int find(int p) { while(p != id[p]) p = id[p]; return p; } public void union(int p, int q){ int pRoot = find(p); int qRoot = find(q); if(pRoot == qRoot) return; id[pRoot] = qRoot; count--; } } 

加权值quick-union

第二个方法已经快了很多

在这里插入图片描述
然后都是一样的
在这里插入图片描述
最后一个就不画了 3上面连个4
你会发现这样的情况遍历还是很多 树的高度呈线性增长
我们在实际的应用只关心两者联合在一起了 也就是两个团伙结盟在一起的问题




所以我们何不让小团伙依附于大团伙呢?

所以我们要在API里加一个成员变量

private int[] sz; 
public WeightedQuickUnion(int N) { count = N; id = new int[N]; sz = new int[N]; for(int i = 0; i < N; i++) { id[i] = i; sz[i] = 1; } } 
public void union(int p, int q){ int pRoot = find(p); int qRoot = find(q); if(pRoot == qRoot) return; if(sz[pRoot] < sz[qRoot]) { id[pRoot] = qRoot; sz[qRoot] += sz[pRoot]; } else { id[qRoot] = pRoot; sz[pRoot] += sz[qRoot]; } count--; } 

完整代码

public class WeightedQuickUnion { private int[] id; private int count; private int[] sz; public WeightedQuickUnion(int N) { count = N; id = new int[N]; sz = new int[N]; for(int i = 0; i < N; i++) { id[i] = i; sz[i] = 1; } } public int getCount() { return count; } public boolean connected(int p, int q) { return find(p) == find(q); } public int find(int p) { while(p != id[p]) p = id[p]; return p; } public void union(int p, int q){ int pRoot = find(p); int qRoot = find(q); if(pRoot == qRoot) return; if(sz[pRoot] < sz[qRoot]) { id[pRoot] = qRoot; sz[qRoot] += sz[pRoot]; } else { id[qRoot] = pRoot; sz[pRoot] += sz[qRoot]; } count--; } } 

路径压缩加权值quick-union

实现方法也简单 其他的不变修改find就行

public int find(int p) { if(p != id[p]) id[p] = find(id[p]); return id[p]; } 

最终版代码 路径压缩加权值quick-union

public class UnionFind { private int[] id; private int count; private int[] sz; public UnionFind(int N) { count = N; id = new int[N]; sz = new int[N]; for(int i = 0; i < N; i++) { id[i] = i; sz[i] = 1; } } public int getCount() { return count; } public boolean connected(int p, int q) { return find(p) == find(q); } public int find(int p) { if (p != id[p]) id[p] = find(id[p]); return id[p]; } public void union(int p, int q){ int pRoot = find(p); int qRoot = find(q); if(pRoot == qRoot) return; if(sz[pRoot] < sz[qRoot]) { id[pRoot] = qRoot; sz[qRoot] += sz[pRoot]; } else { id[qRoot] = pRoot; sz[pRoot] += sz[qRoot]; } count--; } } 

最后的最后让我们分析一下时间复杂度

 存在N伙强盗增长数量级(最坏情况) 算法 构造函数 union() find() union-find算法 O(n) O(n) O(1) quick-union算法 O(n) 树的高度 树的高度 加权quick-union算法 O(n) O(lgn) O(lgn) 路径压缩的加权quick-union算法 O(n) 非常接近O(1) 非常接近O(1) 理想情况 O(n) O(1) O(1) 

大家帮我点个赞呗?!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/234037.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 【Windows11来了】立刻安装Windows11预览版抢先体验(虚拟机 | 含详细安装步骤)

    【Windows11来了】立刻安装Windows11预览版抢先体验(虚拟机 | 含详细安装步骤)本文介绍了使用虚拟机安装Windows11预览版操作系统的过程,并体验了一下新系统

    2022年7月16日
    17
  • 代码生成器原理及示例

    在三层架构中Model、DAL、BLL层有必要分开,其中有些代码可以由代码生成器生成。虽然网络已经有成熟的代码生成器,但是掌握代码生成器的编写方法、原理还是很有必要的。下面通过一个例子简要介绍代码生成器编写过程,并给出一个具备基本功能的范例雏形。以抛砖引玉。

    2022年4月9日
    52
  • python google auth totp_Google Authenticator TOTP原理详解(以Python为例)「建议收藏」

    python google auth totp_Google Authenticator TOTP原理详解(以Python为例)「建议收藏」如果有疑问,请点击此处,然后发表评论交流,作者会及时回复(也可以直接在当前文章评论)。——-谢谢您的参考,如有疑问,欢迎交流一、原理详解(图片可以点击然后放大查看)二、验证1、下载Google谷歌身份验证器。2、通过Python的qrcode和pyotp模块生成二维码。3、然后使用下载的谷歌身份验证器扫描生成的二维码如果没有谷歌服务,则选择输入秘钥,在账户明处填入name参数,在秘…

    2025年7月2日
    2
  • 2G到5G基站架构演进[通俗易懂]

    文章目录2G3G4G5G2G2G通信系统采用3级网络架构,即:BTS-BSC-核心网。2G核心网同时包含CS域和PS域。2G通信系统起初主要采用一体式基站架构。一体式基站架构如下图所示,基站的天线位于铁塔上,其余部分位于基站旁边的机房内。天线通过馈线与室内机房连接。一体式基站架构需要在每一个铁塔下面建立一个机房,建设成本和周期较长,也不方便网络架构的拓展。后来发展成为分布式基站架构。分布式基站架构将BTS分为RRU和BBU。其中RRU主要负责跟射频相关的模块,包括4大模块:中频模块、收发信机模块

    2022年4月9日
    50
  • 怎么用sql脚本创建数据库_mysql数据库导入

    怎么用sql脚本创建数据库_mysql数据库导入使用sql脚本建立数据库,可以方便各用户,各数据库之间的复制使用,下面将在cmd中完成上述操作:cmd中mysql基本操作:1.连结mysql:C:\Users\WJ>mysql-h127.0.0.1-uroot-p123456其中-h表示host127.0.0.1表示地址,这里你如果是远程访问的话,直接写上远程地址即可,-u-p分别为用户名及密码;2.查看所有数据库:showdatabases;3.操作某一数据库:useschool_2;4.查看该数据库下的表:s

    2022年9月24日
    3
  • css3 transition用法(很详细)

    css3 transition用法(很详细)解释transition(CSS属性)是transition-property,transition-duration,transition-timing-function和transition-delay的一个简写属性。transition可以为一个元素在不同状态之间切换的时候定义不同的过渡效果。以下是属性解释。值描述transition-property指定CSS属性的name,transition效果transition-durationtransit

    2022年7月14日
    16

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号