最小生成树的多核并行算法【范本模板】.pdf
《最小生成树的多核并行算法【范本模板】.pdf》由会员分享,可在线阅读,更多相关《最小生成树的多核并行算法【范本模板】.pdf(6页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、最小生成树的多核并行算法 马成刚(09008230)摘要:最小生成树是图论中的经典问题,在现实生活中也有很多应用。本文讨论一种最小生成树的多核并行算法.关键字:最小生成树;索林算法;并行 一、介绍 最小生成树问题是图论中的一个经典问题,也是众多广泛应用的问题之一.关于最小生成树问题已有一些经典的算法,如:Prim 算法、Kruskal 算法,都具有近线性的算法复杂度。对于稀疏图来说,使用 Kruskal 算法更好,否则两种算法复杂性没有什么区别【1】。Prim 算法每次选择一个顶点,Kruskal 算法每次选择一条边,下一个顶点或边是否选择与以前选的顶点或边有关,这样都不适合于并行计算,即当今
2、的多核计算机不能太大提高计算效率。本文介绍一种基于 Sollin 算法的求解最小生成树的多核并行算法,能够提高求最小生成树的并行效率。二、算法 先给出 Sollin 算法 从连通带权简单图G=(V,E)这样产生最小生成树:相继地添加成组的边。假定对V里的顶点进行了排序,这样就产生了一个顺序,其中若u0先于u1,或者若u0=u1并且v0先于v1,则u0,v0 先于 u1,v1。这个算法首先同时选择每个顶点关联的权最小的边。在平局的情形下选择在上述顺序里的第一条边.这样就产生了一个没有简单回路的图,即一些树组成的森林.其次,对森林里的每棵树,同时选择在该树里的一个顶点与在不同的一棵树里顶点之间最短
3、的边.同样在平局的情况下选择在上述顺序下的第一条边。(这样就产生了一个没有简单回路的图,它包含着比在这一步之前出现的更少的边树)继续进行同样的添加树的过程,指导已选择了n1条边为止.(摘自【1】第 576 页)以我对该算法的理解,该算法可以分为三个步骤:选择边、合并顶点、合并边依次循环直到结束.选择边即选择连接每个顶点的权值最小的边,在相同权值的情况下选序号小的;合并顶点将通过选择的边的连通的树中的所有顶点合并成一个新的顶点,进入下一次循环;合并边(在原算法中并没有)用新顶点之间边的权值代替原来树中所有顶点与另一棵树所有顶点之间边的权的最小值,以避免重复查看比较.我没有见过对 Sollin 算
4、法的证明,但这是很简单的.这里给出 Sollin 算法正确性的简单证明。先证明每个顶点关联的权最小的边至少有一个(对有相同的)最终被选到最小生成树中。用反证法如果一个顶点关联的最小的边不被选到最小生成树中,则在最小生成树中添加这条边一定会出现环,这个顶点有两条边在环上。可以去掉其中一条使其成为树.除非这两条边的权值相同即都为最小的边,否则去掉另一条边(不是最小的边)得到的树比最小生成树的总权值小,违反了最小生成树的定义。在证明不会有环产生。点合并和边合并明显不会有环产生。如果产生了环,假设 v1v2,vn构成了环,则是 v1选择了边(v1,v2),v2 选择了边(v2,v3)或反向。由于选择的
5、边都是各个顶点关联的最小权的边,则有 w12w23w34w12(wij表示边(vi,vj)的权值),则 w12=w23=w34=w12。同理,反向也可以得到相同的结论。又由于规定当权值相同时选择序号小的边,如果有环必不符合这条规则.因此可以证明不会出现环。最后证明算法一定会终止.表示算法终止可以用选了 n1 条边,也可以用最后剩下一棵树,易证明两个条件是等价的。在每一次循环,至少是两个顶点结合成一棵树,再把树合并成新顶点,这样顶点数目就减少了一半。循环进行,顶点一定会变为 1。(由此可见,该算法的复杂度是线性的)接下来我们分别就每个步骤讨论一下其并行实现。1.选择边 申请数组存放每一个顶点连接
6、到的边的最小值和所对应的边,对所有边进行遍历,找到连接到各个顶点的最小权值和对应的边。我们知道,图的边的存储方式可以是多种多样的,如邻接表,邻接矩阵,再次为方便采用邻接矩阵讨论,此算法也同样适合其他表示方式,而且效率不会相差太大。对于一个邻接矩阵,可以对每一个顶点并行的求其最小值。按下标从小到大依次遍历,同时可以保证相同权值下标最小。2.合并顶点 将通过选择的边的连通的所有顶点合并成一个新的顶点,进入下一次循环。这里用数组实现的链表。对于每一个顶点分配一个 int型空间,保存与它相邻的一个顶点的索引。为了便于对联标处理,这里规定,每个顶点保存的顶点的索引必须小于该顶点的索引。接下来将原顶点与新
7、顶点对应,即原顶点保存新顶点的索引。用 nn 表示新的顶点个数,对链表从小到大遍历,如果不是指向下一个顶点,那么它就是第一个对应新的索引为 nn 的顶点,新顶点数 nn 加一。由于已经规定链表中的相邻顶点的索引小于当前顶点的索引,可以直接把链表中相邻顶点对应的新顶点的索引给当前顶点.3.合并边 生成新的邻接表权值设为无穷大,遍历当前图的每一条边,如果这条边的两个顶点对应同一个新顶点则跳过。否则判断是否比当前新的邻接表中对应的两个新顶点确定的边的权值小,如果是,则更新新的邻接表中这条边的权值。在这个算法中很多地方都用求最小值。在看多核计算与并行程序设计【2】有关 lock-free 算法的介绍,
8、即多个线程同时访问同一块资源时(比如同时写),能保证至少有一个线程操作的结果是正确的,其他线程判断操作是否正确,如果不正确,则重复操作。对于求数组最小值,可不可以循环判断目标值是否比要写的数值大,如果是则写入,不是就跳过?这样做很容易想到的一个问题是线程调度,如果判断过之后要写,但是写之前线程发生了切换,当其他线程将自己发现的最小值写入后,这个线程恢复执行,不加判断地将等待写入的值写入,就可能出错了(其实这样的概率是很小的,我在测试的时候没有发现过出错,前提是线程数不要太多)。可不可以控制线程在某一段内不被打断或打断之后回到段首开始执行,我以为原子操作是【2】,后来发现那是针对特定操作的。希望
9、操作系统和 CPU 尽快提供对求数组最小值的 lockfree 算法的支持.没有 lock-free 算法,也是加锁是不可接受的.比如说对一个有10000 个点的完全图,权值是 065535 随机(测试是这样的)需要第一次合并有 nn 个顶点(测试结果接近 2500),这样需要(nn1)*nn/2 把锁,总共开合(100001)10000/2 次,这样时间和空间代价都是不可接受的.在此提出一种解决方法:将访问同一块内存的操作交给同一个线程做,这样线程既可以并行,又可以避免冲突。这样需要对第二步合并顶点进行修改,即对指向相同新的顶点的原顶点的表示做修改,使能够很快找到指向相同顶点的原顶点,一种很
10、好的实现方式就是链表了。在上面的基础上进行以下操作:申请一个长度为 nn 的 int 型数组 head,作为新顶点指向原顶点的头指针,初始化为1.对原数组从后向前遍历,对每一个原顶点,将对应新顶点 head 里的值给原顶点的链表,将原顶点的索引赋给对应新顶点的 head,这样 head 里的值就是当前遍历到的对应于该新顶点的最前面一个原顶点,原顶点的链表指向下一个指向相同新顶点的原顶点,这其实就是建立链表的过程。在第三步合并边中,将按原邻接表遍历改为按新邻接表遍历,对于新邻接表中的每一条边的两个顶点,可以很快由链表找到对应它的所有原顶点.这样并没有增加很多工作,但测试时会发现效率明显降低,这将
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 范本模板 最小 生成 多核 并行 算法 范本 模板
限制150内