`

可供快速查找的数据结构和算法总结之一并查集

阅读更多
最近学习了并查集、线段树、树状数组以及RMQ(Range Minimum Query)这几种关于快速查找
的数据结构和算法,并做了一些ACM的题目巩固了一下。准备写一下总结。
本次总结一下并查集:
并查集对解决不相交集合的合并查找操作非常有效,主要提供了一下几个方法:
make_set(x) 把每一个元素初始化为一个集合
find_set(x) 查找一个元素所在的集合
union_set(x,y) 合并x,y所在的两个集合
空间复杂度为O(N),建立一个集合的时间复杂度为O(1),N次合并M查找的时间复杂度为O(M Alpha(N)),
这里Alpha是Ackerman函数的某个反函数,在很大的范围内这个函数的值可以看成是不大于4的,所以并
查集的操作可以看作是线性的。
并查集针对不同的问题有两种不同的实现:
第一种:
make_set(x)的时候parent[x] = x,也就是根的parent指向自己,以此来判断这个元素是否为根元素,
rank值记录树的高度,合并的时候尽量让小的合并到大的集合上,这样可以减少数的高度。
代码如下:
int parent[50001];
int rank[50001];

void make_set(int x){
	parent[x] = x;
	rank[x] = 0;
}

//查找的时候,进行路径压缩parent[x] = find_set(parent[x]),
//把查找路径上的结点都指向跟结点,减小树的高度
int find_set(int x){
	if(x != parent[x]) parent[x] = find_set(parent[x]);
	return parent[x];
}

void union_set(int x,int y){
	int r1 = find_set(x);
	int r2 = find_set(y);
	if(r1 == r2) return;//如果两个元素在相同的集合中,直接retun;

	if(rank[r1] < rank[r2]//把rank值较小的集合合并到达的集合中
		parent[r2] = r1;
	else{
		if(rank[r1] == rank[r2])//两个rank值相等的树合并后rank要增加一
			rank[r2] += 1;
		parent[r1] = r2;
	}
}

第二种:
make_set的时候把parent[x] = -1,根节点parent记录了该集合元素个数
的相反数,所以这种方法很适合想知道某个元素所在的集合的个数的情况。
int parent[30001];

void make_set(int x){
	parent[x] = -1;
}

int find_set(int x){
	int p = x;
	while(parent[p] > 0) p = parent[p];//找到跟结点
	while(x != p){//查找并压缩路径,让查找路径上的每一个x的parent[x] = p,p为根节点
		int temp = parent[x];
		parent[x] = p;
		x = temp;
	}
	return x;
}

void union_set(int x,int y){
	int r1 = find_set(x);
	int r2 = find_set(y);

	if(r1 == r2) return;
	if(parent[r1] < parent[r2]){//集合小的合并到集合大的上,并更新集合元素个数的计数
		parent[r1] += parent[r2];
		parent[r2] = r1;
	}else{
		parent[r2] += parent[r1];
		parent[r1] = r2;
	}
}


以下是这两种并查集的两道ACM应用,可以巩固一下学习的知识:
poj2524 http://acm.pku.edu.cn/JudgeOnline/problem?id=2524
这道题目的主要意思是:n个大学生,指出m对宗教信仰相同的学生,然后让你估算这n个学生中最多
有多少种宗教信仰。
这道题很简单,把宗教数初始化为学生数n,对给出的每对大学生i,j,如果他们在不同的集合,那么
就合并,然后宗教的数量减一
以下是AC的代码:
#include<iostream>
using namespace std;

int parent[50001];
int rank[50001];

void make_set(int x){
	parent[x] = x;
	rank[x] = 0;
}

int find_set(int x){
	if(x != parent[x]) parent[x] = find_set(parent[x]);
	return parent[x];
}

void union_set(int x,int y){
	int r1 = find_set(x);
	int r2 = find_set(y);
	if(r1 == r2) return;

	if(rank[r1] < rank[r2])
		parent[r2] = r1;
	else{
		if(rank[r1] == rank[r2])
			rank[r2] += 1;
		parent[r1] = r2;
	}
}

int main(){
	int m,n;
	int ncases = 0;
	int i = 0;
	while(cin >> n >> m, n){
		int a,b;
		++ncases;
		for(i = 0; i < n; i++){
			make_set(i);	
		}

		for(i = 0; i < m; i++){
			cin >> a >> b;
			int x = find_set(a);
			int y = find_set(b);
			if(x != y){//不同的集合,合并并减一
				n--;
				union_set(x,y);
			}
		}
		cout << "Case " << ncases << ": " << n << endl;
	}
	return 0;
}

poj 1611 The Suspects http://acm.pku.edu.cn/JudgeOnline/problem?id=1611
这道题的意思是有一种传染病SARS,学生有很多的groups,如果groups的一个学生是疑似患者Suspect,
则整个组的其他人都是Suspects,但一个人可能属于不同的组,初始0是suspect,问学生中有多少个
Suspects.
这个题目很简单,把同一组的人进行合并,然后查找一个0元素所在集合元素的个数,由于要统计一个
集合元素的个数,所以使用第二种构造并查集的方法。
AC的代码:
#include<iostream>
using namespace std;

int parent[30001];

void make_set(int x){
	parent[x] = -1;
}

int find_set(int x){
	int p = x;
	while(parent[p] > 0) p = parent[p];
	while(x != p){
		int temp = parent[x];
		parent[x] = p;
		x = temp;
	}
	return x;
}

void union_set(int x,int y){
	int r1 = find_set(x);
	int r2 = find_set(y);

	if(r1 == r2) return;
	if(parent[r1] < parent[r2]){
		parent[r1] += parent[r2];
		parent[r2] = r1;
	}else{
		parent[r2] += parent[r1];
		parent[r1] = r2;
	}
}

int main(){
	int n,m,i = 0;
	while(cin >> n >> m, n){
		for(i = 0; i < n; i++){
			make_set(i);
		}

		for(i = 0; i < m; i++){
			int k;
			cin >> k;
			int first_s,s;
			cin >> first_s;
			for(int j = 1; j < k; j++){
				cin >> s;
				union_set(first_s,s);
			}
		}
		cout << -parent[find_set(0)] << endl;
	}
	return 0;
}

其他来自fandy_wang总结中提供的一些相关题目:
POJ 1182 食物链
并查集的拓展注意: 只有一组数据;
要充分利用题意所给条件:有三类动物A,B,C,这三类动物的食物链
构成了有趣的环形。A吃B, B吃C,C吃A。也就是说:只有三个group
POJ 2492 A Bug's Life 并查集的拓展
法一:深度优先遍历
每次遍历记录下该点是男还是女,只有:男-〉女,女-〉男满足,否则,找到同性恋,结束程序。
法二:二分图匹配
法三:并查集的拓展:和1182很像,只不过这里就有两组,而1182是三组,1611无限制
POJ 1861 Network == zju_1542    并查集+自定义排序+贪心求"最小生成树"
答案不唯一,不过在ZOJ上用QSORT()和SORT()都能过,在POJ上只有SORT()才能过...
POJ 1703 Find them, Catch them 并查集的拓展
这个和POJ 2492 A Bug's Life很像,就是把代码稍微修改了一下就AC了!
注意:And of course, at least one of them belongs to Gang Dragon, and the same for Gang Snake. 就是说只有两个组。
POJ 2236 Wireless Network        并查集的应用
需要注意的地方:1、并查集;2、N的范围,可以等于1001;3、从N+1行开始,第一个输入的可以是字符串。
POJ 1988 Cube Stacking            并查集很好的应用
1、与 银河英雄传说==NOI2002 Galaxy一样;2、增加了一个数组behind[x],记录战舰x在列中的相对位置;3、详细解题报告见银河英雄传说。
JOJ 1905 Freckles   == POJ 2560 最小生成树
法一:Prim算法;法二:并查集实现Kruskar算法求最小生成树
JOJ 1966 Super Market III == PKU 1456 Supermarket 带限制的作业排序问题(贪心+并查集)
提高题目:
POJ 2912 Rochambeau
POJ 1733 Parity game   
POJ 1308 Is It A Tree?
0
0
分享到:
评论

相关推荐

    高级数据结构(一些实用的数据结构算法)

    《高级数据结构》是一本由Peter Brass编写,剑桥大学出版社出版的专业书籍。本书旨在为读者提供深入学习数据结构的机会,特别是那些对于计算机科学有着较高追求的学生或专业人士。本书不仅涵盖了基础数据结构,还...

    清华大学严蔚敏数据结构习题集(C版)答案

    数据结构是计算机科学中的核心课程之一,它研究如何在计算机中高效地组织和管理数据,以便进行快速查找、插入和删除等操作。严蔚敏教授的《数据结构》一书,是中国计算机教育的经典教材,其C语言版本更是深受广大...

    qslim算法,LOD的实现

    1. **数据预处理**:对空间对象进行分割和编码,生成适合索引的数据结构。 2. **LOD构建**:创建多级细节表示,每一级对应不同的空间分辨率。 3. **索引构建**:基于LOD构建高效的索引结构,如B树、R树或四叉树等。 ...

    算法中最小K元素的选择问题

    在计算机科学中,"算法中最小K元素的选择问题"是一个重要的数据结构和算法主题,它涉及到从一个无序或有序的数组中找到第K小(或大)的元素。这个问题在各种应用场景中都有广泛的应用,比如数据库查询优化、排序算法...

    最小生成树_kruskal

    并查集是一种支持快速查找和合并操作的数据结构,对于Kruskal算法来说,其主要作用在于检测环路。并查集的操作包括: - **Find(x)**:返回顶点x所在的集合的代表元素,用于确定顶点x和另一个顶点y是否在同一集合中...

    Challenge-programming-contest:挑战程序设计竞赛2算法和数据结构pdf及源码-源码程序

    《挑战程序设计竞赛2》是一本专注于算法和数据结构的编程竞赛指南,旨在帮助参赛者提升在编程竞赛中的表现。这本书结合了理论与实践,深入浅出地讲解了各种常用的算法和数据结构,并且提供了相应的源码供读者学习和...

    关系查询处理和查询优化

    在查询操作的具体实现中,以选择操作和连接操作为例,有多种算法可供选择: #### 选择操作的实现 1. **全表扫描**:当查询条件较为简单或没有适用的索引时,DBMS会遍历整个表的每一行,检查是否满足查询条件。虽然...

    15届蓝桥杯知识点大纲

    17. 数据结构:包括ST表、堆、树状数组、线段树、Trie树、并查集、平衡树等高级数据结构。 18. 计算几何:包括基础计算和基本位置关系判定、概率论、博弈论等计算几何知识点。 19. 字符串:包括AC自动机、拓展KMP、...

    MATLAB实现学生成绩查询系统 源代码程序.zip

    根据查询条件,我们可以对整个数据集进行快速查找。 结果展示通常涉及数据可视化。MATLAB的绘图功能强大,可以创建表格、图表或数据显示窗口来呈现查询结果。例如,我们可以使用`uitable`显示一个包含查询结果的...

    Java Spatial Index.zip

    JSI的核心思想是通过数据结构和算法将空间数据组织起来,以便在进行空间查询时能够减少搜索范围,提高性能。通常,这种索引会基于某种特定的数据结构,如R树、quadtree或B树等,这些数据结构设计的目的就是处理多维...

    PGM索引:learned先进的学习数据结构,可在数十亿个项目的数组中以比传统索引少几个数量级的空间进行快速查找,前身,范围搜索和更新

    PGM索引是一种创新的学习数据结构,专门设计用于在大规模数据集,特别是包含数十亿项目的数组中执行高效、节省空间的查找、前驱查询、范围搜索和更新操作。这一技术结合了机器学习与传统数据库索引方法,为处理...

    易语言模块新查询快捷方式.rar

    在易语言中,模块是一个可重用的代码单元,它可以封装一系列相关的函数、过程或者数据结构,方便开发者在不同的程序中调用。新查询快捷方式模块可能包含了针对数据库查询、字符串查找、数组搜索等常见查询任务的高效...

    C/C++快件管理系统

    【C/C++快件管理系统】是一个使用C或C++编程语言实现的软件系统,它主要用于模拟和管理快递行业的日常操作。...尽管描述中提到代码可供参考,但真正理解和掌握这些知识点,还需要亲自实践和研究源码。

    11.2_C语言大一课程实验_

    排序是计算机科学中的核心概念,有多种算法可供选择,比如冒泡排序、选择排序、插入排序和快速排序等。学生在项目中不仅需要实现至少一种排序算法,还应理解其基本思想和优缺点。例如,冒泡排序虽然简单易懂,但在...

    全文检索原理

    对结构化数据的搜索,例如使用SQL查询数据库,或者在Windows中基于文件名、类型、修改时间等元数据进行搜索,通常较为高效,因为数据有明确的结构可供算法利用。然而,对非结构化数据的搜索,如在文档内容中查找特定...

    基于正则表达式的字符串查询系统

    2. **匹配引擎**:这是系统的核心,它使用解析器生成的数据结构来匹配目标字符串。对于DFA,匹配过程相对直观;而对于NFA,需要考虑回溯和分支的可能性。匹配引擎可能涉及到动态规划或贪心算法等复杂策略。 3. **...

    IR.rar_IR java_in

    2. **索引构建**:将处理后的文本转化为可供快速查询的索引结构,如倒排索引(Inverted Index)。 3. **查询处理**:接受用户输入的查询,对其进行解析和扩展,生成相应的查询表示。 4. **相关性计算**:根据查询...

    下拉框模糊查询-combo-select-master

    模糊查询的核心在于实现一种搜索算法,该算法能在用户输入关键词时实时过滤并显示与之匹配的选项。常见的模糊查询算法有Levenshtein距离、Jaccard相似度、Tf-Idf等,但针对下拉框的简单模糊查询,一般使用更轻量级的...

    IDL培训教材(基于IDL8.0)-Esri培训班教材

    它提供了一个交互式的环境,使用户能够快速地开发和测试算法,同时拥有丰富的图形显示能力,适合于处理大型数据集。 #### 二、IDL的优势 1. **高效的数据处理能力**:IDL能够快速处理大量的科学数据,尤其在图像和...

    Python库 | grapl_analyzerlib-0.1.48.tar.gz

    "Analyzer"一词通常与数据处理、逻辑推理和问题诊断相关联,而"Lib"是库(Library)的缩写,表明这是一组可供其他程序使用的函数或类。"Grapl"可能代表图形分析(Graph Analysis)或某种特定的数据结构,如图数据...

Global site tag (gtag.js) - Google Analytics