【笔试题】并查集实现

并查集(UnionSet)是一种树型的数据结构,用于处理一些不相交集合)的合并及查询问题。常常在使用中以森林来表示。

并查集实现了将N个不同的元素分成一组不相交的集合。开始时,每个元素就是一个集合,然后按规律将两个集合进行合并。

比如:现在有 0,1,2,3,4,5,6,7,8,9 总共10个元素。它们组成了3个集合,如图:

开始时,将每个元素都当做一个单元素的集合,并将每个元素都初始化为-1,如图:

根据集合按规律将两两集合进行合并, 6、7、8属于0这个集合,所以把6、7、8这三个位置都置0,而0这个位置减去3;1和2这两个集合类似,4和9都属于1这个集合,所以将4、9这两个位置都置为1,并将位置1的数据减2;3、5同属于集合2,所以将位置3、5的数据置为2,将位置2的数据减去2,即:

这样我们可以根据负数的个数清晰的看出有几个集合,并且我们也可以清晰的看出某节点是属于哪个集合的。有3个负数,所以有3个集合,3、5位置数据为2,所以它们属于集合2;6、7、8位置的数据都为0,所以它们都属于集合0;4、9属于集合集合1.

集合的合并:  

形如:

把集合1合并到集合0中,集合1有1、4、9三个元素,所以,将位置1设置为0,并将位置0的数据减去3,即:

由上图我们可以看出4、9属于集合1,集合1又属于集合0;此时数组中共有2个负数,因此有两个集合!

代码实现:

class UnionSet
{
public:
	UnionSet(size_t size)
		:_size(size)
		, _array(new int[size])
	{
		for (int i = 0; i < size; i++)
		{ //将集合的每个元素都初始化为-1
			_array[i] = -1;
		}
	}
	//合并两个集合
	void Merge(int root1, int root2)
	{
                //找到root1所在集合的代表元素和root2所在集合的代表元素,链接
		while (_array[root2] >= 0)
		{
			root2 = _array[root2];
		}
		while (_array[root1] >= 0)
		{
			root1 = _array[root1];
		}
		_array[root1] += _array[root2];
		_array[root2] = root1;
	}
	//查找root对应集合的(根)代表元素
	int Find(int root)
	{
		while (_array[root]>=0)
		{
			root = _array[root];
		}
		return root;
	}
	//打印
	void Print()
	{
		for (int i = 0; i < _size; i++)
		{
			cout << _array[i] << " ";
		}
		cout << endl;
	}

public:
	int* _array;
	size_t _size;
};

 

笔试题:

假如已知有n个人和m对好友关系(存于数组r),如果两个人是直接的或间接的好友关系(好友的好友的好友....),则认为他们属于同一好友圈,请求出这n个人中有几个好友圈。

例如:n=5,m=3,r={{1,2},{2,3},{4,5}},表示有5个人,1和2是好友,2和3是好友,4和5是好友,则1.2.3属于一个朋友圈,4.5属于一个另朋友圈,结果为两个朋友圈。

最后请分析所写代码的时间、空间复杂度。  

这个题用利用并查集实现会比较简易和高效!

需要建立一个函数来计算朋友圈的个数:

//计算朋友圈个数
int friends(int n, int m, int r[][2]) //n元素个数,m为每个朋友圈元素个数
{
	UnionSet uf(n + 1);
	//初始化朋友圈
	for (int i =0 ; i <= m; i++)
	{
		int first = r[i][0];
		int second = r[i][1];
		uf.Merge(first, second);
	}
	uf.Print();
	//计算朋友圈的个数
	int count = 0;
	for (int i = 1; i <= n; i++)
	{
		if (uf._array[i] < 0)
		{
			count++;
		}
	}
	return count;
}

  

 

时间: 2024-08-24 15:23:55

【笔试题】并查集实现的相关文章

Ant Trip HDU - 3018(欧拉路的个数 + 并查集)

题意: Ant Tony和他的朋友们想游览蚂蚁国各地. 给你蚂蚁国的N个点和M条边,现在问你至少要几笔才能所有边都画一遍.(一笔画的时候笔不离开纸) 保证这M条边都不同且不会存在同一点的自环边. 也就是蚂蚁分组遍历整个无向图,他们试图把所有的人分成几个小组,每个小组可以从不同的城镇开始. Tony想知道最少需要几组.  Input输入包含多组测试用例,由多个空行分隔. 每个测试用例的第一行是两个整数N(1<=N<=100000).M(0<=M<=200000),表明蚂蚁国有N个城镇

java各公司笔试题集1

IBM笔试题 注:IBM笔试题一小时之内完成,题目全部用英文描述,这里用中文表述 一.名词解释 1.Eclipse 2.J2EE 3.EJB 4.Ajax 5.Web service 二.找出以下代码问题 public class test{ public void print(String str){ char[] s=str: } } public class a{ public static void main(String [] args){ puts() } } 三.写出以下输出 pu

笔试题合集

2017网易校招内推笔试题:http://blog.csdn.net/luoshixian099/article/details/52102841 携程2017笔试题回忆录:http://blog.csdn.net/miqiong9993/article/details/52565683 完美世界2017c++游戏开发:笔试题+面试题:http://blog.csdn.net/zziymt/article/details/52524419 华为机试 迷宫最短路径 http://blog.csdn

算法初级面试题05——哈希函数/表、生成多个哈希函数、哈希扩容、利用哈希分流找出大文件的重复内容、设计RandomPool结构、布隆过滤器、一致性哈希、并查集、岛问题

今天主要讨论:哈希函数.哈希表.布隆过滤器.一致性哈希.并查集的介绍和应用. 题目一 认识哈希函数和哈希表 1.输入无限大 2.输出有限的S集合 3.输入什么就输出什么 4.会发生哈希碰撞 5.会均匀分布,哈希函数的离散性,打乱输入规律 public class Code_01_HashMap { public static void main(String[] args) { HashMap<String, String> map = new HashMap<>(); map.p

嵌入式Linux C笔试题积累(转)

http://blog.csdn.net/h_armony/article/details/6764811 1.   嵌入式系统中断服务子程序(ISR) 中断是嵌入式系统中重要的组成部分,这导致了很 多编译开发商提供一种扩展—让标准C支持中断.具代表事实是,产生了一个新的关键字 __interrupt.下面的代码就使用了__interrupt关键字去定义了一个中断服务子程序(ISR),请评论一下这段代码的. __interrupt double compute_area (double radi

C/C++ 笔试题

/////转自http://blog.csdn.net/suxinpingtao51/article/details/8015147#userconsent# 微软亚洲技术中心的面试题!!! 1.进程和线程的差别. 线程是指进程内的一个执行单元,也是进程内的可调度实体.与进程的区别:(1)调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位(2)并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可并发执行(3)拥有资源:进程是拥有资源的独立单位,线程不拥有系统资源,但可以访问

非常全的linux面试笔试题及答案

非常全的linux面试笔试题及答案 一.填空题:1. 在Linux系统中,以 文件 方式访问设备 .2. Linux内核引导时,从文件/etc/fstab 中读取要加载的文件系统.3. Linux文件系统中每个文件用 i节点来标识.4. 全部磁盘块由四个部分组成,分别为引导块 .专用块 . i节点表块 和数据存储块.5. 链接分为: 硬链接 和 符号链接 .6. 超级块包含了i节点表 和 空闲块表等重要的文件系统信息.7. 某文件的权限为:d-rw-_r--_r--,用数值形式表示该权限,则该八

【转】嵌入式软件工程师经典笔试题

嵌入式软件工程师经典笔试题 > 预处理器(Preprocessor) 1. 用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题) #define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL 我在这想看到几件事情: 1). #define 语法的基本知识(例如:不能以分号结束,括号的使用,等等) 2). 懂得预处理器将为你计算常数表达式的值,因此,直接写出你是如何计算一年中 有多少秒而不是计算出实际的值,是更清晰而没有代价的. 3).

BZOJ-4423 : [AMPPZ2013]Bytehattan (对偶图+并查集)

4423: [AMPPZ2013]Bytehattan Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 189  Solved: 122[Submit][Status][Discuss] Description 比特哈顿镇有n*n个格点,形成了一个网格图.一开始整张图是完整的.有k次操作,每次会删掉图中的一条边(u,v),你需要回答在删除这条边之后u和v是否仍然连通. Input 第一行包含两个正整数n,k(2<=n<=1500,1<=k&l