并查集(小米面试题求朋友圈的个数)


(一)并查集的引入

以小米的这道题为例

并查集(小米面试题求朋友圈的个数)_第1张图片

     并查集定义:并查集实际上是右一个数组实现的,这个数组比较特殊,最开始将数组的每一个数据看成一个单独的集合,用-1表示。然后根据题目要求1和2可以合并,将第2个数据合并到1上时,array[1]+=array[2],array[2]=1(数组的array[1]保存其与array[2]累加的值,这个值为负,array[2]保存他合并到的那个结点)

并查集(小米面试题求朋友圈的个数)_第2张图片

通过并查集保存过后的数据如上图所示,那么最后只需要计数数组中负数的个数就是朋友圈的个数。

(二)实现代码

由于面试的时候有两种选择,使用类或直接用函数实现,我这里给出两种方式的代码:

1.使用C++类:

测试时包上头文件即可

class UnionFindSet
{
private:
	int *_array;
	size_t _size;
public:
	UnionFindSet()
		:_array(NULL)
		, _size(0)
	{}
	UnionFindSet(int size)
		:_array(new int[size])
		, _size(size)
	{
		memset(_array, -1, sizeof(size_t)*size);
	}
	int FindRoot(int child)
	{
		if (_array[child] > 0)
		{
			return _array[child];
		}
		else
		{
			return child;
		}
	}
	void Combine(int child1, int child2)
	{
		int root1 = FindRoot(child1);
		int root2 = FindRoot(child2);
	
		_array[root1] += _array[root2];
		_array[root2] = root1;

	}
	int FriendCount()
	{
		int count=0;
		for (int i = 0; i <_size; i++)
		{
			if (_array[i] < 0)
			{
				count++;
			}
		}
		return count;
	}
};
int Friends(int n, int m, int r[][2])
{
	UnionFindSet FindFriends(n);
	for (int i = 0; i < m; i++)
	{
		FindFriends.Combine(r[i][0], r[i][1]);
	}
	int friendsCount = FindFriends.FriendCount()-1;
	cout << "一共有" << friendsCount << "个朋友圈"<

2.直接C++写函数

# include
using namespace std;
# include"UnionFindSet.h"
//不写类实现并查集方法求朋友圈个数
int FindRoot(int *&array, int child)
{
	if (array[child] > 0)
	{
		return array[child];
	}
	else
	{
		return child;
	}
}
int FriendsCount(int n,int m,int r[][2])
{
	int*array = new int[n];
	memset(array, -1, sizeof(int)*n);
	for (int i = 0; i < m; i++)//合并两个集合
	{
		int root1 = FindRoot(array,r[i][0]);
		int root2 = FindRoot(array,r[i][1]);
		
		array[root1] += array[root2];
		array[root2] = root1;
	}
	int count = 0;
	for (int i = 0; i < n; i++)
	{
		if (array[i] < 0)
		{
			count++;
		}
	}
	cout << "朋友圈的个数为:" << count - 1 << endl;
	return count - 1;

}

int main()
{
	int r[3][2] = { 1, 2, 2, 3, 4, 5 };
	FriendsCount(5, 3, r);
}




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