数据结构学习之并查集

此文首发于Yucohny
我就是原作者

一、基本操作

1.初始化

void init() {
	for(int i = 1; i < N; i++)
		f[i] = i;
}

2.路径压缩

int find(int x) {
	return f[x]==x ? x : f[x] = find(f[x]);
}

3.合并

void merge(int x, int y) {
	f[find(x)] = find(y);
}

4.求集合数量

int size() {
	int cnt = 0;
	for(int i = 1; i <= n; i++)
		if(f[i] == i)
			cnt++;
	return cnt;
}

二、例题

1.模板题:洛谷1551

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
class Union_Find_Sets{
public:
	int f[N];
	void init(int n) {
		for(int i = 1; i <= n; i++)
			f[i] = i;
	}
	int find(int x) {
		return f[x]==x ? x : f[x] = find(f[x]);
	}
	void merge(int x, int y) {
		f[find(x)] = find(y);
	}
};
int main() {
	Union_Find_Sets s;
	int n, m ,q;
	scanf("%d%d%d",&n,&m,&q);
	s.init(n);
	for(int i = 1; i <= m; i++) {
		int x, y;
		scanf("%d%d", &x, &y);
		s.merge(x, y);
	}
	for(int i = 1; i <= q; i++) {
		int x, y;
		scanf("%d%d", &x, &y);
		if(s.find(x) == s.find(y))
			puts("Yes");
		else
			puts("No");
	}
	return 0;
}

2.模板题:LeetCode 547

class Solution {
public:
	int f[205];
	void init() {
		for(int i = 1; i <= 200; i++)
			f[i] = i;
	}
	int find(int x) {
		return f[x]==x ? x : f[x]=find(f[x]);
	}
	void merge(int x, int y) {
		f[find(x)] = find(y);
	}
    int findCircleNum(vector<vector<int> >& isConnected) {
		int n = isConnected.size(), cnt = 0;
		init();
		for(int i = 0; i < n; i++)
			for(int j = i+1; j < n; j++)
				if(isConnected[i][j])
					merge(i+1,j+1);
		for(int i = 1; i <= n; i++)
			if(f[i] == i)
				cnt++;
		return cnt;
    }
};

3.LeetCode 684

我的链接

三、后言

事实上,在LeetCode上,可以用并查集解题的还有许多,很多题目都可以拿来练练手,如200,此处就不再过多举例。
对于很多纯并查集的题,我们也可以通过宽搜深搜进行解决,但是当并查集与其他数据结构或者算法结合起来时,深搜宽搜未必就有那么实用了。
而对于并查集的时间复杂度,维基百科这样说明:

对于同时使用路径压缩和按秩合并优化的不交集森林,每个查询和合并操作的平均时间复杂度仅为 O ( α ( n ) ) , α ( n ) O(\alpha (n)),\alpha (n) O(α(n)),α(n)是反阿克曼函数。由于阿克曼函数 A A A增加极度迅速,所以 α ( n ) \alpha (n) α(n)增长极度缓慢,对于任何在实践中有意义的元素数目 α ( n ) \alpha (n) α(n)均小于5,因此,也可以粗略地认为,并查集的操作有常数的时间复杂度。
实际上,这是渐近最优算法:Fredman 和 Saks 在 1989 年解释了 Ω ( α ( n ) ) \Omega (\alpha (n)) Ω(α(n))的平均时间内可以获得任何并查集。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值