并查集的概念与算法实现

1、定义

        并查集支持查找一个元素所属的集合以及合并两个元素各自所属的集合等运算。当给出两个元素的一个无序对(a,b),需要快速“合并”a和b所在的集合时,需要反复“查找”元素的集合,“并”、“查”和“集”三字由此而来。

2、应用

并查集主要用于处理一些不相交集合的合并及查询问题,它可以高效的解决一些等价类问题。

3、实现

(1)并查集的树结构类型定义

typedef int ElemType;

//union-find set
typedef struct UFSTNode
{
	ElemType data;
	int rank;
	int parent;
}UFSTNode;

(2)并查集的建立

void MAKE_SET(UFSTNode ufs[], ElemType _data[], int n)
{
	for (int i = 0; i < n; i++)
	{
		ufs[i].data = _data[i];
		ufs[i].parent = i;
		ufs[i].rank = 1;
	}
}

(3)并查集的查找

int FIND_SET(UFSTNode ufs[], int x)
{
	while (x != ufs[x].parent)
		x = ufs[x].parent;
	return x;
}

(4)并查集的合并

void UNION(UFSTNode ufs[], int x, int y)
{
	int s_x = FIND_SET(ufs, x);
	int s_y = FIND_SET(ufs, y);
	if (s_x > s_y)
		ufs[s_y].parent = s_x;
	else
	{
		ufs[s_x].parent = s_y;
		if (ufs[s_x].rank == ufs[s_y].rank)
			ufs[s_y].rank++;
	}
}

4、测试

        问题: 亲威关系问题。现给出一些亲戚关系的信息,如Marry和Tom是亲戚,Tom希

扫描二维码关注公众号,回复: 1462421 查看本文章

Ben是亲戚等。从这些信息中,推出Marry 和Ben是否是亲戚。

        输入: 第一部分以N,M开始。N 为问题涉及的人的个数(1<=N<=20000),这些人的家
号为1,2,3,…,N。下面有M行(1<=M<=1000000),每行有两个数a,b,表示已知 ai 和 bi 是亲威。
        第二部分以Q 开始。以下Q行有Q个询问(1<=Q<=1000000),每行为ci,di,表示询向

ci和di是否为亲戚。

        输出: 对于每个询问ci,di,若 ci 和 di 为亲戚,则输出"Yes”,否则输出“No"。

        输入样例:

        10 7

        2 4 

        5 7

        1 3 

        8 9

        1 2

        5 6

        2 3

        3

        3 4

        7 10

        8 9

#include <iostream>
using namespace std;

typedef int ElemType;

//union-find set
typedef struct UFSTNode
{
	ElemType data;
	int rank;
	int parent;
}UFSTNode;

void MAKE_SET(UFSTNode ufs[], ElemType _data[], int n)
{
	for (int i = 0; i < n; i++)
	{
		ufs[i].data = _data[i];
		ufs[i].parent = i;
		ufs[i].rank = 1;
	}
}

int FIND_SET(UFSTNode ufs[], int x)
{
	while (x != ufs[x].parent)
		x = ufs[x].parent;
	return x;
}

void UNION(UFSTNode ufs[], int x, int y)
{
	int s_x = FIND_SET(ufs, x);
	int s_y = FIND_SET(ufs, y);
	if (s_x > s_y)
		ufs[s_y].parent = s_x;
	else
	{
		ufs[s_x].parent = s_y;
		if (ufs[s_x].rank == ufs[s_y].rank)
			ufs[s_y].rank++;
	}
}

int main()
{
	//input
	const int n = 11, m = 7, q = 3;
	const ElemType data[n] = {};
	const int relate_set[m][2] = { {2, 4}, {5, 7}, {1, 3}, {8, 9}, {1, 2}, {5, 6}, {2, 3} };
	const int query_set[q][2] = { {3, 4}, {7, 10}, {8, 9} };
	//execute
	UFSTNode* ufs = new UFSTNode[n];
	MAKE_SET(ufs, const_cast<ElemType*>(data), n);
	for (int i = 0; i < m; i++)
	{
		UNION(ufs, relate_set[i][0], relate_set[i][1]);
	}
	//output
	for (int i = 0; i < q; i++)
	{
		if (FIND_SET(ufs, query_set[i][0]) == FIND_SET(ufs, query_set[i][1]))
			cout << "Yes" << endl;
		else
			cout << "No" << endl;
	}
	//clear
	delete[] ufs;
	system("pause");
	return 0;
}

参考文献

[1] 李春葆.数据结构教程.清华大学出版社,2013.

猜你喜欢

转载自blog.csdn.net/f1033774377/article/details/80083503