一、基本概念
并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。集就是让每个元素构成一个单元素的集合,也就是按一定顺序将属于同一组的元素所在的集合合并。在一些有N个元素的集合应用问题中,通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。
1、概念
在一些应用问题中,需要将n个不同的元素划分成一组不相交的集合。开始时,每个元素自成一个单元素集合,然后按一定的规律将归于同一组元素的集合合并。在此过程中要反复用到查询某一个元素归属于那个集合的运算。适合于描述这类问题的抽象数据类型称为并查集(union-find set)。
2、场景
- 并查集中需要两种数据类型的参数:集合名类型和集合元素的类型。在许多情况下,可以用整数作为集合名。如果集合中有n个元素,可以用0~n-1以内的整数来表示元素。实现并查集的一个典型方法是采用树形结构来表示元素及其所属子集的关系。
- 每个集合以一棵树表示,树的每一个结点代表集合的一个单元素。所有各个集合的全集合构成一个森林,并用树与森林的父指针表示来实现。其下标代表元素名。第i个数组元素代表集合元素i的树结点。树的根节点的下标代表集合名称,根节点的父为-1,表示集合中的元素个数。
其中:集合中的数字代表集合中元素的个数
集合中的负号表示有几个集合
如下图所示:
总结:在父指针数组表中,在同一棵树上所有节点所代表的集合元素在同一个子集合中。对于任意给定的集合元素x,只要借助这个映射就能找到存放x的树节点,沿此存放x结点的父指针向上一直走到树的根节点,就可以得到x所在集合的名字。
二、并查集的实现
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<iostream>
using namespace std;
#include<vector>
class UFS
{
public:
UFS(size_t size)//对并查集的集合进行初始化
:_vt(size,-1)//利用vector中自身的构造函数,对其进行初始化,方式一
{
//_vt.resize(size, -1);//利用resiz函数,方式2
//方式三
/*int i = 0;
for (; i < size; ++i)
{
_vt[i] = -1;
}*/
}
int Find(int root)
{
while (_vt[root] >= 0)
{
root = _vt[root];
}
return root;
}
void UnionSet(int x1, int x2)
{
if (x1 > _vt.size() || x2 > _vt.size())
return;
int a = Find(x1);
int b = Find(x2);
_vt[a] += _vt[b];
_vt[b] = a;
}
size_t Count()//查看集合中有几个子集合
{
int count = 0;
int i = 0;
for (; i < _vt.size();++i)
{
if (_vt[i] < 0)
count++;
}
return count;
}
private:
vector<int> _vt;
};
void Test()
{
UFS u(10);
u.UnionSet(0, 3);
u.UnionSet(3, 4);
u.UnionSet(4, 5);
u.UnionSet(8, 9);
u.UnionSet(1, 2);
u.UnionSet(2, 6);
u.UnionSet(6, 7);
u.UnionSet(81, 9);//越界元素
cout << u.Count() << endl;
}
结果如下所示:
对于并查集的概念,大概就这么多了,在后面还会给出一些关于并查集的应用,希望大家多多关注。
只有不停的奔跑,才能不停留在原地!!!