Java中的union_Java 并查集Union Find

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

union

isConnected

public interface UF {

int getSize();

boolean isConnected(int p,int q);

void unionElements(int p,int q);

}

public class UnionFind1 implements UF{

private int[] id;

public UnionFind1(int size){

id=new int[size];

for (int i = 0; i < id.length; i++) {

id[i]=i;

}

}

@Override

public int getSize(){

return id.length;

}

//查找元素p所对应的集合编号

private int find(int p) {

if(p<0&&p>id.length)

throw new IllegalArgumentException("p is out of bound.");

return id[p];

}

//查看元素p和元素q是否所属一个集合

@Override

public boolean isConnected(int p,int q){

return find(p)==find(q);

}

//合并元素p和元素q所属的集合

@Override

public void unionElements(int p,int q){

int pID=find(p);

int qID=find(q);

if(pID==qID)

return;

for (int i = 0; i < id.length; i++) {

if(id[i]==pID)

id[i]=qID;

}

}

}

由子数指向父的并差集

public class UnionFind2 implements UF {

private int[] parent;

public UnionFind2(int size){

parent =new int[size];

for(int i=0;i

parent[i]=i;

}

@Override

public int getSize(){

return parent.length;

}

//查找过程,查找元素p所对应的集合编号

private int find(int p){

if(p<0&&p>=parent.length)

throw new IllegalArgumentException("p is out of bound.");

while (p!=parent[p])

p=parent[p];

return p;

}

//查找元素p和元素q是否所属一个集合

@Override

public boolean isConnected(int p,int q){

return find(p)==find(q);

}

//合并元素p和元素q所属的集合

@Override

public void unionElements(int p,int q){

int pRoot =find(p);

int qRoot=find(q);

if(pRoot==qRoot)

return;

parent[pRoot]=qRoot;

}

}

测试:

import java.util.Random;

public class Main {

private static double testUF(UF uf,int m ){

int size=uf.getSize();

Random random =new Random();

long startTime=System.nanoTime();

for(int i=0;i

int a=random.nextInt(size);

int b=random.nextInt(size);

uf.unionElements(a, b);

}

for (int i = 0; i < m; i++) {

int a=random.nextInt(size);

int b=random.nextInt(size);

uf.isConnected(a, b);

}

long endTime=System.nanoTime();

return (endTime-startTime)/1000000000.0;

}

public static void main(String[] args){

int size=10000;

int m=10000;

UnionFind1 uf1=new UnionFind1(size);

System.out.println("UnionFind1:"+testUF(uf1, m)+"s");

UnionFind2 uf2=new UnionFind2(size);

System.out.println("UnionFind1:"+testUF(uf2, m)+"s");

}

}

第三种:(size)

public class UnionFind3 implements UF{

private int[] parent; // parent[i]表示第一个元素所指向的父节点

private int[] sz; // sz[i]表示以i为根的集合中元素个数

// 构造函数

public UnionFind3(int size){

parent = new int[size];

sz = new int[size];

// 初始化, 每一个parent[i]指向自己, 表示每一个元素自己自成一个集合

for(int i = 0 ; i < size ; i ++){

parent[i] = i;

sz[i] = 1;

}

}

@Override

public int getSize(){

return parent.length;

}

// 查找过程, 查找元素p所对应的集合编号

// O(h)复杂度, h为树的高度

private int find(int p){

if(p < 0 || p >= parent.length)

throw new IllegalArgumentException("p is out of bound.");

// 不断去查询自己的父亲节点, 直到到达根节点

// 根节点的特点: parent[p] == p

while( p != parent[p] )

p = parent[p];

return p;

}

// 查看元素p和元素q是否所属一个集合

// O(h)复杂度, h为树的高度

@Override

public boolean isConnected( int p , int q ){

return find(p) == find(q);

}

// 合并元素p和元素q所属的集合

// O(h)复杂度, h为树的高度

@Override

public void unionElements(int p, int q){

int pRoot = find(p);

int qRoot = find(q);

if(pRoot == qRoot)

return;

// 根据两个元素所在树的元素个数不同判断合并方向

// 将元素个数少的集合合并到元素个数多的集合上

if(sz[pRoot] < sz[qRoot]){

parent[pRoot] = qRoot;

sz[qRoot] += sz[pRoot];

}

else{ // sz[qRoot] <= sz[pRoot]

parent[qRoot] = pRoot;

sz[pRoot] += sz[qRoot];

}

}

第四种:(rank)

public class UnionFind4 implements UF {

private int[] rank; // rank[i]表示以i为根的集合所表示的树的层数

private int[] parent; // parent[i]表示第i个元素所指向的父节点

// 构造函数

public UnionFind4(int size){

rank = new int[size];

parent = new int[size];

// 初始化, 每一个parent[i]指向自己, 表示每一个元素自己自成一个集合

for( int i = 0 ; i < size ; i ++ ){

parent[i] = i;

rank[i] = 1;

}

}

@Override

public int getSize(){

return parent.length;

}

// 查找过程, 查找元素p所对应的集合编号

// O(h)复杂度, h为树的高度

private int find(int p){

if(p < 0 || p >= parent.length)

throw new IllegalArgumentException("p is out of bound.");

// 不断去查询自己的父亲节点, 直到到达根节点

// 根节点的特点: parent[p] == p

while(p != parent[p])

p = parent[p];

return p;

}

// 查看元素p和元素q是否所属一个集合

// O(h)复杂度, h为树的高度

@Override

public boolean isConnected( int p , int q ){

return find(p) == find(q);

}

// 合并元素p和元素q所属的集合

// O(h)复杂度, h为树的高度

@Override

public void unionElements(int p, int q){

int pRoot = find(p);

int qRoot = find(q);

if( pRoot == qRoot )

return;

// 根据两个元素所在树的rank不同判断合并方向

// 将rank低的集合合并到rank高的集合上

if(rank[pRoot] < rank[qRoot])

parent[pRoot] = qRoot;

else if(rank[qRoot] < rank[pRoot])

parent[qRoot] = pRoot;

else{ // rank[pRoot] == rank[qRoot]

parent[pRoot] = qRoot;

rank[qRoot] += 1; // 此时, 我维护rank的值

}

}

}

第五种:(路径压缩)

public class UnionFind5 implements UF {

// rank[i]表示以i为根的集合所表示的树的层数

// 在后续的代码中, 我们并不会维护rank的语意, 也就是rank的值在路径压缩的过程中, 有可能不在是树的层数值

// 这也是我们的rank不叫height或者depth的原因, 他只是作为比较的一个标准

private int[] rank;

private int[] parent; // parent[i]表示第i个元素所指向的父节点

// 构造函数

public UnionFind5(int size){

rank = new int[size];

parent = new int[size];

// 初始化, 每一个parent[i]指向自己, 表示每一个元素自己自成一个集合

for( int i = 0 ; i < size ; i ++ ){

parent[i] = i;

rank[i] = 1;

}

}

@Override

public int getSize(){

return parent.length;

}

// 查找过程, 查找元素p所对应的集合编号

// O(h)复杂度, h为树的高度

private int find(int p){

if(p < 0 || p >= parent.length)

throw new IllegalArgumentException("p is out of bound.");

while( p != parent[p] ){

parent[p] = parent[parent[p]];

p = parent[p];

}

return p;

}

// 查看元素p和元素q是否所属一个集合

// O(h)复杂度, h为树的高度

@Override

public boolean isConnected( int p , int q ){

return find(p) == find(q);

}

// 合并元素p和元素q所属的集合

// O(h)复杂度, h为树的高度

@Override

public void unionElements(int p, int q){

int pRoot = find(p);

int qRoot = find(q);

if( pRoot == qRoot )

return;

// 根据两个元素所在树的rank不同判断合并方向

// 将rank低的集合合并到rank高的集合上

if( rank[pRoot] < rank[qRoot] )

parent[pRoot] = qRoot;

else if( rank[qRoot] < rank[pRoot])

parent[qRoot] = pRoot;

else{ // rank[pRoot] == rank[qRoot]

parent[pRoot] = qRoot;

rank[qRoot] += 1; // 此时, 我维护rank的值

}

}

}

第六种:(递归)

public class UnionFind6 implements UF {

// rank[i]表示以i为根的集合所表示的树的层数

// 在后续的代码中, 我们并不会维护rank的语意, 也就是rank的值在路径压缩的过程中, 有可能不在是树的层数值

// 这也是我们的rank不叫height或者depth的原因, 他只是作为比较的一个标准

private int[] rank;

private int[] parent; // parent[i]表示第i个元素所指向的父节点

// 构造函数

public UnionFind6(int size){

rank = new int[size];

parent = new int[size];

// 初始化, 每一个parent[i]指向自己, 表示每一个元素自己自成一个集合

for( int i = 0 ; i < size ; i ++ ){

parent[i] = i;

rank[i] = 1;

}

}

@Override

public int getSize(){

return parent.length;

}

// 查找过程, 查找元素p所对应的集合编号

// O(h)复杂度, h为树的高度

private int find(int p){

if(p < 0 || p >= parent.length)

throw new IllegalArgumentException("p is out of bound.");

// path compression 2, 递归算法

if(p != parent[p])

parent[p] = find(parent[p]);

return parent[p];

}

// 查看元素p和元素q是否所属一个集合

// O(h)复杂度, h为树的高度

@Override

public boolean isConnected( int p , int q ){

return find(p) == find(q);

}

// 合并元素p和元素q所属的集合

// O(h)复杂度, h为树的高度

@Override

public void unionElements(int p, int q){

int pRoot = find(p);

int qRoot = find(q);

if( pRoot == qRoot )

return;

// 根据两个元素所在树的rank不同判断合并方向

// 将rank低的集合合并到rank高的集合上

if( rank[pRoot] < rank[qRoot] )

parent[pRoot] = qRoot;

else if( rank[qRoot] < rank[pRoot])

parent[qRoot] = pRoot;

else{ // rank[pRoot] == rank[qRoot]

parent[pRoot] = qRoot;

rank[qRoot] += 1; // 此时, 我维护rank的值

}

}

}

4bb6073696eaec791f170a71655dca01.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值