并查集原理及应用

并查集

树形的数据结构,每个集合有其代表节点,代表节点相同的元素属于同一集合。
find:通过查找节点的代表节点,判断节点所属集合。
union:合并两集合,小集合合并到大集合,使用大集合的代表节点。

class UnionFindSet {
private:
	unordered_map<int, int> fatherMap;
	unordered_map<int, int> nodesNum;
public:
	UnionFindSet(vector<int> vec)
	{//初始化时,每个节点各自一个集合
		for (int i : vec)
		{
			fatherMap[i] = i;
			nodesNum[i] = 1;
		}
	}
	/*
		查找代表节点(父节点是自身)
		如果当前节点不是代表节点,就递归查找,直到找到。
		在递归的回退过程中,令路过每个节点的父节点直接改为代表节点,
		在下次查找该集合元素时可以提高查找速度,不用再递归。
	*/
	int find(int x)
	{
		if (fatherMap[x] == x)
			return x;
		else
			return fatherMap[x] = find(fatherMap[x]);
	}
	//合并两个节点所在的集合,小集合合并到达集合上
	void unionSet(int a, int b) {
		int father_a = find(a);
		int father_b = find(b);
		if (father_a != father_b) {
			int num_a = nodesNum[father_a];
			int num_b = nodesNum[father_b];
			if (num_a > num_b) {
				fatherMap[father_b] = father_a;//大集合是爸爸
				nodesNum[father_a] += num_b;
			}
			else {
				fatherMap[father_a] = father_b;
				nodesNum[father_b] += num_a;
			}
		}
	}
};

find的递归过程中,让路过节点的父节点直接赋值为代表节点,节省下次查找时间,如图所示。
在这里插入图片描述

  • 计算岛的个数
如果有一片1连在一起, 这个部分叫做一个岛, 求一个矩阵中有多少个岛?
举例:
0 0 1 0 1 0
1 1 1 0 1 0
1 0 0 1 0 0
0 0 0 0 0 0
这个矩阵中有三个岛

遍历二维数组,遇到1时就将所相连的1都改为2,看看遇到多少次1,就是岛的数量。改数时使用回溯(类似于走迷宫)。回溯的基本过程:

  • 如果符合条件:
    • 执行改动
    • 递归向下一层
    • 撤消改动

但是我们希望在递归的回退过程中,将执行的改动保留下来,因此不需要第三步。

void infect(vector<vector<int>>& mat, int i, int j)
{
	int m = mat.size(), n = mat[0].size();
	if (i >= 0 && i < m && j >= 0 && j < n && mat[i][j] == 1)
	{
		mat[i][j] = 2;
		infect(mat, i - 1, j);
		infect(mat, i + 1, j);
		infect(mat, i, j - 1);
		infect(mat, i, j + 1);
	}
}

int isolationNum(vector<vector<int>> mat)
{
	if (mat.empty() || mat[0].empty()) return 0;
	int m = mat.size(), n = mat[0].size();
	int res = 0;
	for (int i = 0; i < m; i++)
	{
		for (int j = 0; j < n; j++)
		{
			if (mat[i][j] == 1) {
				res++;
				infect(mat, i, j);
			}
		}
	}
	return res;
}

当矩阵较大,可以通过并行计算分别计算每块的岛屿数量,然后再合并集合,没合并一次计数减一。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值