B站灯笼哥大神(海外名校博士)并查集笔记

B站灯笼哥(海外名校博士)并查集笔记

import org.junit.Test;
public class Math {
    //并查集,判断无向连通图中是否有环(通过点合并在集合当中)
    // 克鲁斯卡尔算法便是使用的并查集方式
    //算法步骤分析:
    //1.先准备好parent数组,初始化为-1,表示其没有父节点处于最顶层
    //2.构建集合将有联系的数放在一个集合中,那么这个过程是通过合并得到的
    //3.判断图中是否有环,根据每一条边使用find_root来找到,如果结果相同那么说明有环:
    //原因:结果相同代表我们的这两个点是有一条路径可以到达的,而你在输入这两个点时又是一条边,故成环
    //注意:在一个集合里表示元素之间是可以相互到达的
    int find_root(int x,int[] parent)
    {
            while(parent[x]!=-1)
                x=parent[x];
            return  x;
    }
    boolean union_verticles(int x,int y,int[] parent)
    {
        int x_root  = find_root(x,parent);
        int y_root = find_root(y,parent);
        if(x_root==y_root)
        {
            return  false;//成环,合并失败
        }
        else {
            parent[x_root]=y_root;
            return true;
        }
    }
    void initialize(int[] parent){
        for(int i=0;i<parent.length;i++)
            parent[i]=-1;
    }
    @Test
    public void Test()
    {
        int edges[][] = {{1,2},{3,4},{2,3}};
        int parent[] = new int[5];
	    initialize(parent);
        boolean flag=true;
        for(int i=0;i<edges.length;i++)
        {
            int x = edges[i][0];
            int y = edges[i][1];
            if(!union_verticles(x,y,parent)){
                System.out.println("Circle detected");
                flag =false;
                break;
            }
        }
        if(flag)
        {
            System.out.println("None!");
        }
    }
}

上述代码还存在不足,就是可能会造成构建的集合,这样在查找根节点的过程中会十分耗时,因此我们要进行压缩.使用rank数组来记录每个节点的层数(就是指包括它本身在内往下一共最大多少层),初始化为0
修改代码如下:

import org.junit.Test;
public class Math {
//只修改了union_verticles函数
    int find_root(int x,int[] parent)
    {
            while(parent[x]!=-1)
                x=parent[x];
            return  x;
    }
    boolean union_verticles(int x,int y,int[] parent,int rank[])
    {
        int x_root  = find_root(x,parent);
        int y_root = find_root(y,parent);
        if(x_root==y_root)
        {
            return  false;//成环,合并失败
        }
        else
            {
            if(rank[x_root]>rank[y_root])//说明y_root层数更高一点,连接后两个rank均不变
            {
                parent[y_root]=x_root;
            }
            else if(rank[x_root]<rank[y_root])//说明x_root层数更高一点,连接后两个rank均不变
            {
                parent[x_root]=y_root;
            }else
            {
                parent[x_root]=y_root;//由于层数相同,连接后rank[y_root]会变大,加一层
                rank[y_root]++;//其实这一部分也可以写为parent[y_root]=x_root;rank[x_root]++
            }
            return true;
        }
    }
    void initialize(int[] parent){
        for(int i=0;i<parent.length;i++)
            parent[i]=-1;
    }
    @Test
    public void Test()
    {
        int edges[][] = {{1,2},{3,4},{2,3},{4,2}};
        int parent[] = new int[5];
        int rank[] = new int[5];
        initialize(parent);
        boolean flag=true;
        for(int i=0;i<edges.length;i++)
        {
            int x = edges[i][0];
            int y = edges[i][1];
            if(!union_verticles(x,y,parent,rank)){
                System.out.println("Circle detected");
                flag =false;
                break;
            }
        }
        if(flag)
        {
            System.out.println("None!");
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值