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!");
        }
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章