数据结构 并查集 路径压缩

来源:互联网 发布:水利网络培训 编辑:程序博客网 时间:2024/06/06 07:01

经常会遇到对于给定的n个点,求出他们能否相互连通的问题,常规的做法可能是用二维数组进行标记处理,但是这样的空间使用是O(n^2),当数据量很大的时候,这个消耗是很恐怖的,所以这里我们引入并查集的这种数据结构。

树是一种数据结构,它的特点在于所有的点有且仅有一个根节点,如果我们能构造一棵树,并把所有的树按照相互关系装入这棵树,那么他们就是属于一个集合,他们都互相连通的。

我们可以用数组来构建这样一个模型。

int parent[N]; 

用这样一个数组,记录每个点属于哪个集合,最初所有的点都是孤立的。所以等于它本身。
每次我们都需要查询他们所属的集合,是否为同一个集合,如果不是,就可以把它们连通。
而且我们可以建立简单的树形关系:
这里写图片描述
这样查询的次数为层数。
注意有一种最坏的情况,就是如同链表那样,查询次数就接近总数的一半了。

int findx(int x){    int r=x;   while(parent[r] !=r)        r=parent[r];   return r;}

这里我们给出一个很简单的查询方法,首先用变量r存储需要查询的值,然后每次查询r的父节点,保存它的父节点,查询它父节点的父节点……最后就能找到答案。
但我们想想,对于每个数,我们每次都需要去查询它根节点的时候都要很多时间,而且我们真实需要的并不是它的父节点的值,而是它根节点的值。
如果我们能构建如下的树:
这里写图片描述
这样查询的效率就是O(1),因为只有一层,所以我们查询的时间很少,这里就用到了路径压缩,我们先看压缩过的代码:

int findx(int x)       {    if (x != parent[x])    {        parent[x] = find(parent[x]);         }             return parent[x];}

这样我们每次都会去更新父节点的值变成根节点的值。
但是用递归会出现一种问题,爆堆栈。
windows对堆栈的限制很大,所以我们可以放弃递归,用递推式。

int findx(int x){    int k, j, r;    r = x;    while(r != parent[r])             r = parent[r];          k = x;            while(k != r)                 {        j = parent[k];                 parent[k] = r;                k = j;                        }    return r;                     }

这种非递归方式更安全。

1 0
原创粉丝点击