【数据结构】之实现并查集

#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


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