PS:从今天开始开始认真的按顺序把ACM程序设计竞赛的算法系统的学习一下,并做好的笔记整理,好多可能援引其他人的课件或者博客,我会写出出处的,当然大部分是我自己的原创的,希望各位看官大牛们指教;
言归正传,并查集。
并查集维基百科中是这样描述的:并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。我看到有资料上有写可以用数组实现,可以用链表实现,看得我糊里糊涂的,感觉用树的结构来写实现起来容易,效率也很高;
并查集简单的说就是把一个集合的元素用一个标号来表示,每个节点的最终祖先节点就标记为这个标号。
并查集有三个操作:初始化,合并,查询。
我先贴两个我写的代码来照着代码来说比较容易些,读者也容易读些,本人的代码写得不是很简洁明了,希望大牛们指出不足之处
上述为简单的朴素的并查集,不带任何的优化
chushihua(int n)根据名字也可以看出是初始化函数,也可以看出我的英语很烂,:-)。初始化的时候将每个节点的父节点设为本身,构造一群指向自己的节点的集合;
Max_size设置的是节点的个数,father数组记录的是节点父节点,初始为指向自己。
psfind()传入一个节点的标号,根据标号来寻找其属于集合的标号。找到节点的父节点的标号是其本身就是这个集合的标号,即根节点。
psunion(int root1,int root2)传入连个节点root1,root2,找到两个节点属于的集合标号,然后当不相等的时候合并两个结合就可以了,至于怎么合并,只要把一个节点的标号设置为另一个节点就可以了。
以上就是一个朴素的并查集,不带任何的优化的,当一个集合所形成的树是一个偏的很厉害的树,形成一个链状的树(所有节点都是在父节点的左链上)。每次寻找都是很浪费时间的。对n个节点的寻找的复杂度达到O(n^2)的。
下面我们来看两个优化:
1:rank数组的引入,启发式函数
2:路径压缩;
以上就是带有两个优化的代码;
当没次查询节点的标号的时候,不是找到了就大功告成了,而是把这条路径上的所有的节点的标号就OK了,复杂度接近线性的好像接近O(5*n),是个函数乘以N,细致的算法复杂度分析黑书上都是有的。
rank数组记录的是一个集合形成树的深度,合并的时候把深度小的根节点的父节点设为深度大的那个根节点就OK了的。
貌似并查集简单的就这些了。
http://zh.wikipedia.org/w/index.php?title=%E5%B9%B6%E6%9F%A5%E9%9B%86&variant=zh-cn这个是维基百科关于并查集的东东。
下面给几道简单的推荐题,让大家练下手,实践是唯一的真理呀。。。。
稍后我会写上这些题目的自己做的思路和解题报告,欢迎指教;
http://162.105.81.212/JudgeOnline/problem?id=1703
http://162.105.81.212/JudgeOnline/problem?id=2421
http://162.105.81.212/JudgeOnline/problem?id=2492
http://162.105.81.212/JudgeOnline/problem?id=1861
http://162.105.81.212/JudgeOnline/problem?id=1308
http://162.105.81.212/JudgeOnline/problem?id=2524
希望大家切题快乐,明天写解题报告上传。