并查集——小米笔试题

并查集简介:

并查集(Union-find Sets)是一种非常精巧而实用的数据结构,它主要用于处理一些不相交集合的合并问题。一些常见的用途有求连通子图、求最小生成树的 Kruskal 算法和求最近公共祖先(Least Common Ancestors, LCA)等。

使用并查集时,首先会存在一组不相交的动态集合 S={S1,S2,,Sk}S={S1,S2,⋯,Sk},一般都会使用一个整数表示集合中的一个元素。

每个集合可能包含一个或多个元素,并选出集合中的某个元素作为代表。每个集合中具体包含了哪些元素是不关心的,具体选择哪个元素作为代表一般也是不关心的。我们关心的是,对于给定的元素,可以很快的找到这个元素所在的集合(的代表),以及合并两个元素所在的集合,而且这些操作的时间复杂度都是常数级的。

并查集的实现原理也比较简单,就是使用树来表示集合,树的每个节点就表示集合中的一个元素,树根对应的元素就是该集合的代表,同一个根节点,就在一个集合内。开始时,每个元素都是一个集合,按规律进行合并。

如图:

并查集——小米笔试题_第1张图片

eg:小米笔试题

并查集——小米笔试题_第2张图片

代码实现:

#include
using namespace std;
class UnionSet
{
public:
	UnionSet(int n)
		:_n(n)
	{
		_us = new int[n + 1];
		for (int i = 0; i <= _n; i++)
		{
			_us[i] = -1;
		}
	}
	~UnionSet()
	{
		delete[] _us;
		_us = NULL;
	}
protected:
	int _Findroot(int x)
	{
		while (_us[x] >= 0)
			x = _us[x];
		return x;
	}
public:
	void _Union(int x, int y)
	{
		int root1 = _Findroot(x);
		int root2 = _Findroot(y);
		if (root1 != root2)
		{
			_us[root1] += _us[root2];
			_us[root2] = root1;
		}
	}
	int _GetUnionCount()
	{
		int count = 0;
		for (int i = 0; i <= _n;i ++)
		{
			if (_us[i] < 0)
				count++;
		}
		return --count; //减去_us[0]的-1
	}
protected:
	int* _us;
	int  _n;
};
int _Friendcircle(int n, int m, int r[][2])
{
	UnionSet uf(n);
	for (int i = 0; i < m; i++)
	{
		uf._Union(r[i][0], r[i][1]);
	}
	return uf._GetUnionCount();
}
int main()
{
	int r[][2] = { { 1, 2 }, { 2, 3 }, { 4, 5 }, { 0, 7 }, { 6, 8 } };
	int ret = _Friendcircle(9, 5, r);//当有0的时候  _n=n+1
	cout<< "朋友圈个数:" << ret << endl;
	return 0;
}


你可能感兴趣的:(数据结构及算法)