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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • sqlbulkcopy 使用DataTable作为数据源的数据类型问题–来自数据源的String类型的给定值不能转换为指定目标列的类型 uniqueidentifier…

    sqlbulkcopy 使用DataTable作为数据源的数据类型问题–来自数据源的String类型的给定值不能转换为指定目标列的类型 uniqueidentifier…今天做批量插入的时候,SQLSERVER总是报错,错误提示“来自数据源的String类型的给定值不能转换为指定目标列的类型uniqueidentifier”。首先核对了一下定义的dataTable中的DataColumn[]的顺序和数量,发现和数据库的表结构是一致的,而且把代码中对dataRow[]对应位置赋值的语句屏蔽后,执行成功。因此可以确定主要还是由于类型转换的时候的问题。后来…

    2022年7月20日
    22
  • java出现中文乱码_Java开发中中文乱码总结

    java出现中文乱码_Java开发中中文乱码总结1.jsp页面内容显示乱码这种乱码原因很简单,一般的工具或解码程序对中文字符解析时采用默认的解码方式:我们只需修改其编码方式即可,如下:字符集:UTF-8>GBK>GB23122.jsp与Servlet间跳转出现中文乱码2.1:method=”Post”jsp中form表单的ation=”XxxServlet”,method=”Post”时,提交表单后往往发现中文的属性值在Se…

    2022年7月8日
    15
  • 2005中文博客排名报告「建议收藏」

    2005中文博客排名报告「建议收藏」2005中文博客排名报告发布机构:时代财富科技公司 摘要:2004年11月时代财富科技公司推出了中文Blog排行榜,得到了大众及媒介的广泛关注,也成为众多同行和资本市场了解中文博客网站的重要参考。历经2005年上半年中文Blog托管网站的飞速发展时期,博客网站也正经历着重新的洗牌和残酷的市场竞争。经过长时间的调查和分析,结合大量的用户体验,时代财富科技公司于2005年8月隆重推出《

    2022年7月12日
    13
  • POJ2309 BST

    POJ2309 BST

    2022年2月21日
    36
  • python meshgrid_numpy的生成网格矩阵 meshgrid()

    python meshgrid_numpy的生成网格矩阵 meshgrid()numpy模块中的meshgrid函数用来生成网格矩阵,最简单的网格矩阵为二维矩阵meshgrid函数可以接受x1,x2,…,xn等n个一维向量,生成N-D矩阵。1基本语法meshgrid(*xi,**kwargs)参数:xi-x1,x2,…,xn:array_like返回值:X1,X2,…,XN:ndarray2示例(二维网格)2.1一个参…

    2022年5月27日
    139
  • 更换CSDN博客皮肤[通俗易懂]

    更换CSDN博客皮肤[通俗易懂]1.在博客设置页面F12,如下图,选中博客皮肤:2.把你喜欢的皮肤的value和ID与当前模板value和ID对换,如下图:3.点击保存之后刷新页面,如下图:…

    2022年7月14日
    14

发表回复

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

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