1. 程式人生 > 其它 >7.3 並查集搜尋

7.3 並查集搜尋

並查集演算法

並查集演算法是一個利用結點關係,進行分類合組的演算法

簡介

並查集可以通過一個一維陣列來實現
我們把每一個點視作一個"獨立的,只有一個結點"的樹
之後我們可以通過一些條件,逐漸將這些樹合併成一棵大樹

合併的過程,其實就是找統一的父節點的過程,我們可以自定兩條原則:
1.相異的情況下,把右邊的父節點改為左邊的父節點。視作二者合併成了一組
2.通過兩者最高的父節點來進行比較

另外,既然我們通過層層推進找到了某個點的父節點,那麼我們在"統一"之後,也可以順便的把路上的其它結點修改,這樣會方便我們的二次尋找

程式碼示例

    #include <stdio.h>
    int f[1001] = {0} s,n,m,sum = 0 ;
    
    //最開始的初始化
    void init()
    {
        int i ; 
        for(i=0;i<=n;i++)
            f[i] = i ;//最開始的時候,每個點的最高父節點就是它自己
        return ; 
    }

    //這是找爹的遞迴函式,不停的尋找直到找到最高父節點為止  
    int getf(int v)
    {
        if(f[v] == v){
            return ; //“集團”內只有一個人的情況
        }
        else
        {
            //路徑壓縮,每次在函式返回的時候,順帶把路徑上的結點都修改
            f[v] = getf(f[v]) ;

            return f[v];
        }
    }

    //合併兩個子集的函式、
    void merge(int v , int u)
    {
        int t1,t2 ; //t1,t2指的是兩個子集的最高父節點

        t1 = getf(v);
        t2 = getf(u);

        if(t1!=t2){
            //兩者不在同一集合中,才進行合併
            f[t2] = t1 ; //向左合併原則
        }
        return ; 
    }

    //主程式
    int main()
    {
        int i,x,y;
        scanf("%d %d",&n,&m);

        init();
        for(i=1;i<=m;i++)
        {
            scanf("%d %d",&x,&y);
            merge(x,y);
        }

        //掃描列印結果
        for(i=1;i<=n;i++)
        {
            if(f[i] == i )
                sum++;
        }
        printf("%d \n",sum);


        getchar();getchar()
        return 0 ;
    }

並查集也被稱為“不相交集”資料結構