【數據結構】之實現並查集

#include <stdio.h>

/**
 * 並查集適用於管理元素分組情況的數據結構,本質上是樹結構(不是二叉樹)
 * 可以高效的進行以下操作:
 * 1.判斷兩個元素是否屬於同一組(通過判斷兩個元素的根節點是否一樣即可)
 * 2.合併兩個元素所在的組(把其中一個元素的根節點的父節點指向另一個元素的根節點)
 *
 * 在該實現下,進行一次操作的時間複雜度爲O(a(N))
 * 其中N是元素個數,a(N)是阿克曼函數的反函數(logN還快)
 */

#define N 10
/**
 * 假設開始時10個節點都分別是獨立的一棵樹:
 * 例如par[0]=0 表示0號節點的父節點爲它自己,也就代表整棵樹的根節點就是0號節點。
 * 如果par[0]=1 則表示0號節點的父節點是1號節點
 * 因爲開始時10個節點都是獨立的一棵樹,所以各顆樹的高度rank設爲0
 */
static int par[N]  = {0,1,2,3,4,5,6,7,8,9};
static int rank[N] = {0,0,0,0,0,0,0,0,0,0};


//查找樹的根
int findRoot(int x){
    if (par[x] == x)
        return x;
    /**
     * 每次查找都會順便將沿途的節點進行路徑壓縮,
     * 所謂路徑壓縮,是指把當前節點的父節點直接指向根節點
     * 這樣的話,下一次再次查找該節點的根節點的時候,就可以更快了
     */
    return par[x] = findRoot(par[x]);
}

//合併xy的所屬集合
void unite(int x, int y){
    x = findRoot(x);
    y = findRoot(y);
    //如果發現是同一個集合,則直接返回
    if (x == y)
        return;
    //高度較低的樹要向高度較高的合併,以保持合併後整棵樹的平衡
    if (rank[x] < rank[y]) {
        par[x] = y;
    } else {
        par[y] = x;
        if (rank[x] == rank[y])
            rank[x]++;
    }
}

//判斷兩個節點是否屬於同一集合(判斷是否屬於同一根節點即可)
int same(int x, int y){
    return findRoot(x) == findRoot(y);
}

int main() {
    printf("%d\n", findRoot(2));
    unite(1,2);
    unite(2,3);
    unite(5,3);
    printf("%d\n", findRoot(5));
    printf("is same? %d", same(5,1));
    return 0;
}

運行結果:

2
1
is same? 1


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