数据结构中图结构的最小生成树克鲁斯卡尔算法详解
我一直想把克鲁斯卡尔算法实现,但是由于马上就要考试了,而且自己由于天气寒冷等各种原因没能如愿。不过在昨天一天的努力中,我终于完成了克鲁斯卡尔算法的实现。算法是c++的,图的数据结构是以邻接矩阵为基础,并且使用了模板,所以可以对任何类型的顶点进行最小生成树的生成。
更新于12月19日:由于自己发现了一些错误和解释不清的现象,所以将一张图片和少数文字进行了更正。
克鲁斯卡尔算法中的核心思想就是逐个在边的集合中找到最小的边,如果满足条件就将其构造,最后生成一个最小生成树。它首先是一系列的顶点集合,并没有边,然后我们从邻接矩阵中寻找最小的边,看看它是否和现有的边连接成一个环,如果连接成环,则舍弃,另外取其它的边。如果不连接成环,则接受这个边,并把其纳入集合中。以此类推。我们知道,一课有n个顶点的树(无论是树还是二叉树),它必定有n-1个边。我们只需要对上述操作循环至少n-1次(因为可能选出的边会构成环,不是我们需要的边)。
下面就是我寻找最小边的c++代码:
- min=INFINITY;
-
for(i=0;i<vexnum;i++)
- {
-
for(j=i;j<vexnum;j++)
- {
-
if(arcs[i][j].adj!=INFINITY&&min>arcs[i][j].adj)
- {
-
if(arcs[i][j].adj>=vexSet.lowcost&&!vexSet.IsAlreadyIn(i,j))
- {
- min=arcs[i][j].adj;
- track_i=i;
- track_j=j;
- }
- }
- }
- }
首先让min为最大(INFINITY),然后让其与邻接矩阵的一个个元素进行比较,我在遍历邻接矩阵的时候使用的是上三角(◥)法,因为无向网的邻接矩阵是对称矩阵。当然我们必须记录满足调件的顶点的下标,所以track_i、track_j就变得必要了。又因为我们要满足每次选取的最小权值的边呈递增数列,所以arcs[i][j].adj > vexSet.lowcost(其中vexSet.lowcost为上次保存的最小边)就变得必要了。同时我们还要注意一点,如果一个图有多条边的权值相同(如右图),那么我们必须在这里添加上=号,变成arcs[i][j].adj >= vexSet.lowcost。并且要从顶点集合(VertexSet,稍后会提到)中的顶点位置中查找是否已经存在。这里我使用了IsAlreadyIn()函数来实现它。
然后我们必须要判断我们新加入的边是否和原有边构成环。由于边在邻接矩阵的表现形式是两个顶点的集合。所以这时我们的顶点下标track_i、track_j就派上用场了,它们被保存到vexPos中。这里我写了一个函数(IsCycle()),用来判断是否构成环。
试着考虑下列数列:
1 2 1 3 2 4 3 4
①②③④⑤⑥⑦⑧
其中3 4是我将要加上的边。他们构成的关系图如下所示:(图)
显然加上了3 4的话,就会构成环了。怎样用c++来判断是否构成环呢?我们可以这么考虑:
令x=3,也就是⑦号位的3,然后从①号位开始遍历这个数组,如果找到了3,则记下这个3的位置。这里是④号位。然后如果是偶数号位,那么我们找到它相邻的奇数位,如果是奇数号位,那么我们要找它相邻的偶数号位。这里我们找到③号位1。然后我们再以1为关键字,找到另外一个1。这里找到了①号位。我们再找它的相邻位即②号位2。这时又以2为关键字,遍历数组。此时我们需注意,从左遍历起的时候可能会找到原来的2。这时我们要尽量避免找到它。这里使用一个if语句进行判断即可实现。下面就是我这个函数的代码:
-
-
template<typenameCustomType>
-
boolJMatrixGraph<CustomType>::IsCycle(VertexSet<CustomType>objSet)
- {
-
if(objSet.vexCount==0)returnfalse;
-
ints=objSet.vexCount;
-
CustomTypex=objSet.vertices[s];
-
inti=s;
-
while(1)
- {
-
if(i==0)i=1;
-
elsei=0;
-
for(;objSet.vertices[i]!=x;)
- {
-
if(i>objSet.vexCount+1)returnfalse;
-
if(i+1==s)i+=2;
-
elsei++;
- }
-
if(x==objSet.vertices[objSet.vexCount+1])returntrue;
-
if(i%2!=0)i-=1;
-
elsei+=1;
-
x=objSet.vertices[i];
-
s=i;
- }
- }
-
下面就是我为最小生成树(克鲁斯卡尔算法)这个功能写的代码:
-
-
template<typenameCustomType>
-
boolJMatrixGraph<CustomType>::IsCycle(VertexSet<CustomType>objSet)
- {
-
if(objSet.vexCount==0)returnfalse;
-
ints=objSet.vexCount;
-
CustomTypex=objSet.vertices[s];
-
inti=s;
-
while(1)
- {
-
if(i==0)i=1;
-
elsei=0;
-
for(;objSet.vertices[i]!=x;)
- {
-
if(i>objSet.vexCount+1)returnfalse;
-
if(i+1==s)i+=2;
-
elsei++;
- }
-
if(x==objSet.vertices[objSet.vexCount+1])returntrue;
-
if(i%2!=0)i-=1;
-
elsei+=1;
-
x=objSet.vertices[i];
-
s=i;
- }
- }
-
-
-
template<typenameCustomType>
-
voidJMatrixGraph<CustomType>::MiniSpanTree_KRUSKAL(void)
- {
- VertexSet<CustomType>vexSet;
-
inti,j,k,track_i=0,track_j=0;
-
unsignedintmin;
-
while(vexSet.vexCount!=(vexnum-1)*2)
- {
- min=INFINITY;
-
for(i=0;i<vexnum;i++)
- {
-
for(j=i;j<vexnum;j++)
- {
-
if(arcs[i][j].adj!=INFINITY&&min>arcs[i][j].adj)
- {
-
if(arcs[i][j].adj>=vexSet.lowcost&&!vexSet.IsAlreadyIn(i,j))
- {
- min=arcs[i][j].adj;
- track_i=i;
- track_j=j;
- }
- }
- }
- }
-
vexSet.vertices[vexSet.vexCount]=vexs[track_i];
- vexSet.vertices[vexSet.vexCount+1]=vexs[track_j];
-
vexSet.vexPos[vexSet.vexCount]=track_i,vexSet.vexPos[vexSet.vexCount+1]=track_j;
-
vexSet.lowcost=min;
-
if(!IsCycle(vexSet))vexSet.vexCount+=2;
- }
-
-
#ifdef_JDEBUG_//调试版本的
-
cout<<"邻接矩阵为:/n";
-
for(i=0;i<vexnum;i++)
- {
-
for(j=0;j<vexnum;j++)
- {
-
if(arcs[i][j].adj==INFINITY)
-
cout<<"∞";
-
elsecout<<arcs[i][j].adj<<"";
- }
-
cout<<'/n';
- }
-
#endif
-
-
for(i=0;i<vexSet.vexCount;i+=2)
- {
-
cout<<vexSet.vertices[i]<<"→"<<vexSet.vertices[i+1]<<'/n';
- }
- }
-
为了适应这个算法,必须添加一个新的数据结构。由于这个结构的成员主要以顶点为主,所以命名为VertexSet。下面就是这个数据结构体的定义:
-
template<typenameCustomType>
-
structVertexSet
- {
-
VertexSet():lowcost(0),vexCount(0){}
-
boolIsAlreadyIn(inti_in,intj_in)
- {
-
intk;
-
for(k=0;k<vexCount+2;k+=2)
-
if(vexPos[k]==i_in&&vexPos[k+1]==j_in)returntrue;
-
returnfalse;
- }
-
CustomTypevertices[MAX_VERTEX_NUM];
-
intvexPos[MAX_VERTEX_NUM*(MAX_VERTEX_NUM)/2];
-
VRTypelowcost;
-
intvexCount;
- };
我使用这样的主函数进行调用:
- #define_JDEBUG_//调试的开关(可注释)
-
#include"JGraph.h"
-
intmain(intargc,char**argv)
- {
-
JMatrixGraph<char>jmg;
-
chartemp;
- jmg.CreateGraph(UDN);
-
-
-
cout<<"克鲁斯卡尔算法遍历的结果是:/n";
- jmg.MiniSpanTree_KRUSKAL();
-
return0;
- }
-
-
对照数据结构书上的176页图,我们可以看到克鲁斯卡尔算法中构造最小生成树的过程。
对照数据结构书上的186页图,并改为无向图,我们可以看到克鲁斯卡尔算法中构造最小生成树的过程。
我自己画了一个图,并且在计算机中完美地显示出来了。
克鲁斯卡尔算法是我从昨天就开始着手的工程,直到现在才完工。从这个算法中我得知设计一个算法的重要性。另外,我的算法可能很不高效,远没有书上所讲的效率高(看我那么多for循环就知道了)。但是由于书上和网上没有很多实例,所以我就觉得自己还是要设计一个算法,以后同学们遇到困难的话,这样就不至于迷茫了。希望同学们能够自己开动脑筋,作出比我的算法更加优秀的克鲁斯卡尔算法,我到时候就会看看大家的算法,大家一同努力!
分享到:
相关推荐
利用广度优先算法实现图的遍历,算法结构清晰,比较容易看懂。
data structure 数据结构中图的相关算法 用C代码实现
关于数据结构中图的建立和一些相关的操作!是自己做的,不好的话请高人们给点意见。
#资源达人分享计划#
数据结构中图算法设计题 ★★图的基本操作算法★★ ★★图的遍历算法★★
利用基本的数据结构,对图进行遍历,其中包含非递归算法
在学习数据结构与算法设计这门课程后,本人自制的思维导图,很好的梳理其中的知识,对学习效率的提升有很大的帮助
这是一个数据结构中图创建的程序,已经调试成功,可以使用
数据结构中图的全部操作 #include<stdio.h> #include<stdlib.h> #include<malloc.h> #include<stack> #include <iostream> #include<iomanip> using namespace std; #define MAX_VERTEX_NUM 100 #define INFINITY ...
可以很好的学习数据结构中图的生成,遍历和相关操作,让你更好的懂得图的存储结构
数据结构中图的算法 Red and Black ,Knight Moves,Sorting It All Out,Jungle Roads,Stockbroker Grapevine
数据结构中图的遍历,最小生成树,最短路径等等。
真的是很好的资源,我花了很长时间做出来的。老师都说好,里面注释也很详细,绝对不会让你失望的。
最小生成树是数据结构中图的一种重要应用,它的要求是从一个带权无向完全图中选择n-1条边并使这个图仍然连通(也即得到了一棵生成树),同时还要考虑使树的权最小。 为了得到最小生成树,人们设计了很多算法,最著名...
资源详细的介绍了数据结构中图的最小支撑树实现方式之一普利姆算法的思想和代码实现,并且结合了刘大有数据结构算法的思想以及韩顺平老师讲述的最小支撑树的两种实现。
数据结构的设计与应用 摘要:数据结构是数据的逻辑结构、物理存储结构及算法的封装,本文从这三个方面 讨论如何应用数据结构解决非数值计算的实际问题,并用具体实例说明数据结构的应用 。 关键词:数据结构;栈;...
图的遍历,数据结构,PPT,掌握图的深度优先和广度优先遍历的性质和方法,以及基于邻接矩阵和邻接表存储结构的递归和非递归的算法实现
数据结构中图的遍历问题的源代码 遍历图的各种用法
数据结构中图的拓扑排序,采用邻接矩阵,没有采用栈的操作
数据结构中图的遍历问题的源代码,用C++编写