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


相关推荐

  • 控制误差_自动控制原理校正

    控制误差_自动控制原理校正计算机实时控制加工误差的时滞问题.pdf第18卷薯4月J.Hu中azho理ngUU工nniv杰·ofSS学cci.·&TechhVAOpIr.i18IN19o9.021990档计算机实时控制加工误差的时滞问题薯宾鸿赞(机械工程一系)提要本文从计算机控制的原理分析八手…

    2022年10月1日
    0
  • linux如何卸载jdk版本并重装_centos卸载jdk

    linux如何卸载jdk版本并重装_centos卸载jdklinuxcentos7自带了openjdk,这个版本的jdk是缺少一部分功能的,最好重新安装oraclejdk。但在没有卸载openjdk就安装oraclejdk时,部分依赖包装不上,后期程序运行时会出现问题。以下为卸载jdk的步骤(openjdk或oraclejdk)和安装步骤。#1.查看目前系统中包含的jdk版本rpm-qa|grepjdk#2.得到的结果如下:java-1.8.0-openjdk-1.8.0.322.b06-1.e

    2022年10月1日
    0
  • motan与zookeeper框架[通俗易懂]

    motan与zookeeper框架[通俗易懂]新浪科技讯2016年5月10日,微博方面宣布,支撑微博千亿调用的轻量级RPC框架Motan正式开源了。微博技术团队希望未来能有更多优秀的开源人入驻,并进一步完善优化。搭建新浪RPC框架motanDemo:http://blog.csdn.net/linuu/article/details/53115290 motan是新浪微博开源的RPC框架,github官网是:https:/…

    2022年10月24日
    0
  • Wireshark使用教程

    Wireshark使用教程文章目录安装使用开始捕获以wireshark2.6.3汉化版为例安装除了路径是自定义之外,其它均默认即可。使用开始捕获菜单“捕获-选项”,设置需要捕获的网络适配器,点击“开始”。也可以在菜单“捕获-开始”、“捕获-结束”来控制开始结束。在“捕获-捕获过滤器”编辑捕获表达式在上述“捕获”菜单中进行的操作,也可以在工具栏进行,如下图捕获结果着色规则在菜单“视图-着色规则”…

    2022年6月16日
    30
  • Pycharm 实现远程部署和调试,原来这么简单「建议收藏」

    Pycharm 实现远程部署和调试,原来这么简单「建议收藏」一般代码本地调试完成后,需要运行到服务器上,比如自动化测试脚本、爬虫脚本等,所以第一步需要将项目上传到服务器,然后在服务器上进行调试和运行。但是需要长期维护和开发的项目,这样就繁琐了很多,并且我们时常要维护多个测试或者开发环境,每个环境的Python版本和依赖包有可能还存在差异,这样的话,每次更新需要花费的时间就更多了。其实,很多的编辑器都考虑到这个问题,可以实现远程调试,比如Pycharm、Vscode等。Pycharm可以进行远程部署项目(上传和下载),还可以通过配置远程解释器进行远程调..

    2022年8月28日
    0
  • vue 使用vue-i18n实现中英文语言切换,以及动态添加中英文「建议收藏」

    vue 使用vue-i18n实现中英文语言切换,以及动态添加中英文「建议收藏」一、安装。npminstallvue-i18n二、使用。(这里只写了核心代码)引入://引入插件和语言包importVueI18nfrom’vue-i18n’importzhfrom’@/i18n/langs/zh’importenfrom’@/i18n/langs/en’Vue.use(VueI18n);zh文件:exportdefault{placeStopOrder:”下止损单”,}en文件:exportdef

    2022年5月8日
    143

发表回复

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

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