对于一组数据,主要支持两种动作:

union

isConnected

  1. public interface UF {
  2. int getSize();
  3. boolean isConnected(int p,int q);
  4. void unionElements(int p,int q);
  5. }

  

  1. public class UnionFind1 implements UF{
  2. private int[] id;
  3. public UnionFind1(int size){
  4. id=new int[size];
  5. for (int i = 0; i < id.length; i++) {
  6. id[i]=i;
  7. }
  8. }
  9. @Override
  10. public int getSize(){
  11. return id.length;
  12. }
  13. //查找元素p所对应的集合编号
  14. private int find(int p) {
  15. if(p<0&&p>id.length)
  16. throw new IllegalArgumentException("p is out of bound.");
  17. return id[p];
  18. }
  19. //查看元素p和元素q是否所属一个集合
  20. @Override
  21. public boolean isConnected(int p,int q){
  22. return find(p)==find(q);
  23. }
  24. //合并元素p和元素q所属的集合
  25. @Override
  26. public void unionElements(int p,int q){
  27. int pID=find(p);
  28. int qID=find(q);
  29. if(pID==qID)
  30. return;
  31. for (int i = 0; i < id.length; i++) {
  32. if(id[i]==pID)
  33. id[i]=qID;
  34. }
  35. }
  36.  
  37. }

  由子数指向父的并差集

  1. public class UnionFind2 implements UF {
  2.  
  3. private int[] parent;
  4. public UnionFind2(int size){
  5. parent =new int[size];
  6. for(int i=0;i<size;i++)
  7. parent[i]=i;
  8. }
  9. @Override
  10. public int getSize(){
  11. return parent.length;
  12. }
  13. //查找过程,查找元素p所对应的集合编号
  14. private int find(int p){
  15. if(p<0&&p>=parent.length)
  16. throw new IllegalArgumentException("p is out of bound.");
  17. while (p!=parent[p])
  18. p=parent[p];
  19. return p;
  20. }
  21. //查找元素p和元素q是否所属一个集合
  22. @Override
  23. public boolean isConnected(int p,int q){
  24. return find(p)==find(q);
  25. }
  26. //合并元素p和元素q所属的集合
  27. @Override
  28. public void unionElements(int p,int q){
  29. int pRoot =find(p);
  30. int qRoot=find(q);
  31.  
  32. if(pRoot==qRoot)
  33. return;
  34. parent[pRoot]=qRoot;
  35. }
  36. }

  测试:

  1. import java.util.Random;
  2.  
  3. public class Main {
  4.  
  5. private static double testUF(UF uf,int m ){
  6. int size=uf.getSize();
  7. Random random =new Random();
  8. long startTime=System.nanoTime();
  9. for(int i=0;i<m;i++){
  10. int a=random.nextInt(size);
  11. int b=random.nextInt(size);
  12. uf.unionElements(a, b);
  13. }
  14.  
  15. for (int i = 0; i < m; i++) {
  16. int a=random.nextInt(size);
  17. int b=random.nextInt(size);
  18. uf.isConnected(a, b);
  19. }
  20. long endTime=System.nanoTime();
  21. return (endTime-startTime)/1000000000.0;
  22. }
  23.  
  24. public static void main(String[] args){
  25. int size=10000;
  26. int m=10000;
  27.  
  28. UnionFind1 uf1=new UnionFind1(size);
  29. System.out.println("UnionFind1:"+testUF(uf1, m)+"s");
  30.  
  31. UnionFind2 uf2=new UnionFind2(size);
  32. System.out.println("UnionFind1:"+testUF(uf2, m)+"s");
  33. }
  34. } 

第三种:(size)

  1. public class UnionFind3 implements UF{
  2.  
  3. private int[] parent; // parent[i]表示第一个元素所指向的父节点
  4. private int[] sz; // sz[i]表示以i为根的集合中元素个数
  5.  
  6. // 构造函数
  7. public UnionFind3(int size){
  8.  
  9. parent = new int[size];
  10. sz = new int[size];
  11.  
  12. // 初始化, 每一个parent[i]指向自己, 表示每一个元素自己自成一个集合
  13. for(int i = 0 ; i < size ; i ++){
  14. parent[i] = i;
  15. sz[i] = 1;
  16. }
  17. }
  18.  
  19. @Override
  20. public int getSize(){
  21. return parent.length;
  22. }
  23.  
  24. // 查找过程, 查找元素p所对应的集合编号
  25. // O(h)复杂度, h为树的高度
  26. private int find(int p){
  27. if(p < 0 || p >= parent.length)
  28. throw new IllegalArgumentException("p is out of bound.");
  29.  
  30. // 不断去查询自己的父亲节点, 直到到达根节点
  31. // 根节点的特点: parent[p] == p
  32. while( p != parent[p] )
  33. p = parent[p];
  34. return p;
  35. }
  36.  
  37. // 查看元素p和元素q是否所属一个集合
  38. // O(h)复杂度, h为树的高度
  39. @Override
  40. public boolean isConnected( int p , int q ){
  41. return find(p) == find(q);
  42. }
  43.  
  44. // 合并元素p和元素q所属的集合
  45. // O(h)复杂度, h为树的高度
  46. @Override
  47. public void unionElements(int p, int q){
  48.  
  49. int pRoot = find(p);
  50. int qRoot = find(q);
  51.  
  52. if(pRoot == qRoot)
  53. return;
  54.  
  55. // 根据两个元素所在树的元素个数不同判断合并方向
  56. // 将元素个数少的集合合并到元素个数多的集合上
  57. if(sz[pRoot] < sz[qRoot]){
  58. parent[pRoot] = qRoot;
  59. sz[qRoot] += sz[pRoot];
  60. }
  61. else{ // sz[qRoot] <= sz[pRoot]
  62. parent[qRoot] = pRoot;
  63. sz[pRoot] += sz[qRoot];
  64. }
  65. }

第四种:(rank)

  1. public class UnionFind4 implements UF {
  2.  
  3. private int[] rank; // rank[i]表示以i为根的集合所表示的树的层数
  4. private int[] parent; // parent[i]表示第i个元素所指向的父节点
  5.  
  6. // 构造函数
  7. public UnionFind4(int size){
  8.  
  9. rank = new int[size];
  10. parent = new int[size];
  11.  
  12. // 初始化, 每一个parent[i]指向自己, 表示每一个元素自己自成一个集合
  13. for( int i = 0 ; i < size ; i ++ ){
  14. parent[i] = i;
  15. rank[i] = 1;
  16. }
  17. }
  18.  
  19. @Override
  20. public int getSize(){
  21. return parent.length;
  22. }
  23.  
  24. // 查找过程, 查找元素p所对应的集合编号
  25. // O(h)复杂度, h为树的高度
  26. private int find(int p){
  27. if(p < 0 || p >= parent.length)
  28. throw new IllegalArgumentException("p is out of bound.");
  29.  
  30. // 不断去查询自己的父亲节点, 直到到达根节点
  31. // 根节点的特点: parent[p] == p
  32. while(p != parent[p])
  33. p = parent[p];
  34. return p;
  35. }
  36.  
  37. // 查看元素p和元素q是否所属一个集合
  38. // O(h)复杂度, h为树的高度
  39. @Override
  40. public boolean isConnected( int p , int q ){
  41. return find(p) == find(q);
  42. }
  43.  
  44. // 合并元素p和元素q所属的集合
  45. // O(h)复杂度, h为树的高度
  46. @Override
  47. public void unionElements(int p, int q){
  48.  
  49. int pRoot = find(p);
  50. int qRoot = find(q);
  51.  
  52. if( pRoot == qRoot )
  53. return;
  54.  
  55. // 根据两个元素所在树的rank不同判断合并方向
  56. // 将rank低的集合合并到rank高的集合上
  57. if(rank[pRoot] < rank[qRoot])
  58. parent[pRoot] = qRoot;
  59. else if(rank[qRoot] < rank[pRoot])
  60. parent[qRoot] = pRoot;
  61. else{ // rank[pRoot] == rank[qRoot]
  62. parent[pRoot] = qRoot;
  63. rank[qRoot] += 1; // 此时, 我维护rank的值
  64. }
  65. }
  66. }

  第五种:(路径压缩)

  1. public class UnionFind5 implements UF {
  2.  
  3. // rank[i]表示以i为根的集合所表示的树的层数
  4. // 在后续的代码中, 我们并不会维护rank的语意, 也就是rank的值在路径压缩的过程中, 有可能不在是树的层数值
  5. // 这也是我们的rank不叫height或者depth的原因, 他只是作为比较的一个标准
  6. private int[] rank;
  7. private int[] parent; // parent[i]表示第i个元素所指向的父节点
  8.  
  9. // 构造函数
  10. public UnionFind5(int size){
  11.  
  12. rank = new int[size];
  13. parent = new int[size];
  14.  
  15. // 初始化, 每一个parent[i]指向自己, 表示每一个元素自己自成一个集合
  16. for( int i = 0 ; i < size ; i ++ ){
  17. parent[i] = i;
  18. rank[i] = 1;
  19. }
  20. }
  21.  
  22. @Override
  23. public int getSize(){
  24. return parent.length;
  25. }
  26.  
  27. // 查找过程, 查找元素p所对应的集合编号
  28. // O(h)复杂度, h为树的高度
  29. private int find(int p){
  30. if(p < 0 || p >= parent.length)
  31. throw new IllegalArgumentException("p is out of bound.");
  32.  
  33. while( p != parent[p] ){
  34. parent[p] = parent[parent[p]];
  35. p = parent[p];
  36. }
  37. return p;
  38. }
  39.  
  40. // 查看元素p和元素q是否所属一个集合
  41. // O(h)复杂度, h为树的高度
  42. @Override
  43. public boolean isConnected( int p , int q ){
  44. return find(p) == find(q);
  45. }
  46.  
  47. // 合并元素p和元素q所属的集合
  48. // O(h)复杂度, h为树的高度
  49. @Override
  50. public void unionElements(int p, int q){
  51.  
  52. int pRoot = find(p);
  53. int qRoot = find(q);
  54.  
  55. if( pRoot == qRoot )
  56. return;
  57.  
  58. // 根据两个元素所在树的rank不同判断合并方向
  59. // 将rank低的集合合并到rank高的集合上
  60. if( rank[pRoot] < rank[qRoot] )
  61. parent[pRoot] = qRoot;
  62. else if( rank[qRoot] < rank[pRoot])
  63. parent[qRoot] = pRoot;
  64. else{ // rank[pRoot] == rank[qRoot]
  65. parent[pRoot] = qRoot;
  66. rank[qRoot] += 1; // 此时, 我维护rank的值
  67. }
  68. }
  69. }

  第六种:(递归)

  1. public class UnionFind6 implements UF {
  2.  
  3. // rank[i]表示以i为根的集合所表示的树的层数
  4. // 在后续的代码中, 我们并不会维护rank的语意, 也就是rank的值在路径压缩的过程中, 有可能不在是树的层数值
  5. // 这也是我们的rank不叫height或者depth的原因, 他只是作为比较的一个标准
  6. private int[] rank;
  7. private int[] parent; // parent[i]表示第i个元素所指向的父节点
  8.  
  9. // 构造函数
  10. public UnionFind6(int size){
  11.  
  12. rank = new int[size];
  13. parent = new int[size];
  14.  
  15. // 初始化, 每一个parent[i]指向自己, 表示每一个元素自己自成一个集合
  16. for( int i = 0 ; i < size ; i ++ ){
  17. parent[i] = i;
  18. rank[i] = 1;
  19. }
  20. }
  21.  
  22. @Override
  23. public int getSize(){
  24. return parent.length;
  25. }
  26.  
  27. // 查找过程, 查找元素p所对应的集合编号
  28. // O(h)复杂度, h为树的高度
  29. private int find(int p){
  30. if(p < 0 || p >= parent.length)
  31. throw new IllegalArgumentException("p is out of bound.");
  32.  
  33. // path compression 2, 递归算法
  34. if(p != parent[p])
  35. parent[p] = find(parent[p]);
  36. return parent[p];
  37. }
  38.  
  39. // 查看元素p和元素q是否所属一个集合
  40. // O(h)复杂度, h为树的高度
  41. @Override
  42. public boolean isConnected( int p , int q ){
  43. return find(p) == find(q);
  44. }
  45.  
  46. // 合并元素p和元素q所属的集合
  47. // O(h)复杂度, h为树的高度
  48. @Override
  49. public void unionElements(int p, int q){
  50.  
  51. int pRoot = find(p);
  52. int qRoot = find(q);
  53.  
  54. if( pRoot == qRoot )
  55. return;
  56.  
  57. // 根据两个元素所在树的rank不同判断合并方向
  58. // 将rank低的集合合并到rank高的集合上
  59. if( rank[pRoot] < rank[qRoot] )
  60. parent[pRoot] = qRoot;
  61. else if( rank[qRoot] < rank[pRoot])
  62. parent[qRoot] = pRoot;
  63. else{ // rank[pRoot] == rank[qRoot]
  64. parent[pRoot] = qRoot;
  65. rank[qRoot] += 1; // 此时, 我维护rank的值
  66. }
  67. }
  68. }

  

Java 并查集Union Find的更多相关文章

  1. 并查集(Union/Find)模板及详解

    概念: 并查集是一种非常精巧而实用的数据结构,它主要用于处理一些不相交集合的合并问题.一些常见的用途有求连通子图.求最小生成树的Kruskal 算法和求最近公共祖先等. 操作: 并查集的基本操作有两个 ...

  2. java 并查集

    并查集代码 并查集优化⼀ 并查集优化⼆ 实战题⽬目1. https://leetcode.com/problems/number-of-islands/2. https://leetcode.com/ ...

  3. POJ 1611 The Suspects 并查集 Union Find

    本题也是个标准的并查集题解. 操作完并查集之后,就是要找和0节点在同一个集合的元素有多少. 注意这个操作,须要先找到0的父母节点.然后查找有多少个节点的额父母节点和0的父母节点同样. 这个时候须要对每 ...

  4. java——并查集 UnionFind

    时间复杂度: O(log*n),近乎是O(1)级别的 UnionFind 接口: public interface UF { int getSize(); boolean isConnected(in ...

  5. 最小生成树(Minimum Spanning Tree)——Prim算法与Kruskal算法+并查集

    最小生成树——Minimum Spanning Tree,是图论中比较重要的模型,通常用于解决实际生活中的路径代价最小一类的问题.我们首先用通俗的语言解释它的定义: 对于有n个节点的有权无向连通图,寻 ...

  6. bzoj1854 [Scoi2010]游戏【构图 并查集】

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1854 没想到怎么做真是不应该,看到每个武器都有两个属性,应该要想到连边构图的!太不应该了! ...

  7. [leetcode] 并查集(Ⅰ)

    预备知识 并查集 (Union Set) 一种常见的应用是计算一个图中连通分量的个数.比如: a e / \ | b c f | | d g 上图的连通分量的个数为 2 . 并查集的主要思想是在每个连 ...

  8. 并查集(Java实现)

    (最好在电脑下浏览本篇博客...手机上看代码不方便) 当时学的时候看的一本印度的数据结构书(好像是..有点忘了..反正跟同学们看的都不一样...)...里面把本文提到的所有情况都提到了,我这里只是重复 ...

  9. 并查集的Java实现

    Java实现并查集,合并时采用路径压缩算法. 如果合并时使用循环修改的方法,一次合并的时间复杂度就为N,无法接受 public class Union { public int[] id;//对应索引 ...

随机推荐

  1. bzoj 5301: [Cqoi2018]异或序列 (莫队算法)

    链接:https://www.lydsy.com/JudgeOnline/problem.php?id=5301 题面; 5301: [Cqoi2018]异或序列 Time Limit: 10 Sec ...

  2. Redisson分布式锁实现

    转: Redisson分布式锁实现 2018年09月07日 15:30:32 校长我错了 阅读数:3303   转:分布式锁和Redisson实现 概述 分布式系统有一个著名的理论CAP,指在一个分布 ...

  3. 从redis中取值如果不存在设置值,使用Redisson分布式锁【我】

    用到的jar包: <!-- Redis客户端 --> <dependency> <groupId>redis.clients</groupId> < ...

  4. spring的DI.IoC是什么

    最近要搞spring的单元测试,不得已啊啊啊啊啊啊啊啊啊又要开始搞spring…… 日目晶…… 搞这几个概念,先甩一部分代码: UserDao 接口 package com.itheima.ioc; ...

  5. uboot中的中断macro宏

    目录 uboot中的中断macro宏 引入 内存分配 流程概览 普通中断 保存现场 中断函数打印具体寄存器 恢复现场 软中断 空间获取 保存现场 附录速记 疑惑待解 title: uboot中的中断m ...

  6. 编写高质量的Python代码系列(二)之函数

    Python中的函数具备多种特性,这可以简化编程工作.Python函数的某些性质与其他编程语言中的函数相似,但也有性质是Python独有的.本节将介绍如何用函数来表达亿图.提升可复用程度,并减少Bug ...

  7. Mathematica 代码

    s1 = ContourPlot3D[x^2 + z^2 == 1, {x, -1, 1}, {y, 0, 1}, {z, -1, 1}] s2 = ContourPlot3D[ y == 1 + S ...

  8. python selenium 最简单示例

    使用 pip 安装  selenium 下载 chromedriver,添加在PATH中 # -*- coding: utf-8 -*- from selenium import webdriver ...

  9. 剑指Offer-翻转单词顺序列

    题目描述 牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上.同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思.例如,"st ...

  10. 通过配置文件新建solr的core

    目录solr-7.5.0\server\solr 1.  新建文件夹 test-core 2. 在文件夹test-core下新建core.properties name=test-core confi ...