当前位置:首页 » 操作系统 » 克鲁斯卡尔算法

克鲁斯卡尔算法

发布时间: 2022-01-14 00:43:26

⑴ c加加提问,克鲁斯卡尔算法是什么

克鲁斯卡尔算法,从边的角度求网的最小生成树,时间复杂度为O(eloge)。和普里姆算法恰恰相反,更适合于求边稀疏的网的最小生成树。

对于任意一个连通网的最小生成树来说,在要求总的权值最小的情况下,最直接的想法就是将连通网中的所有边按照权值大小进行升序排序,从小到大依次选择。

由于最小生成树本身是一棵生成树,所以需要时刻满足以下两点:

  • 生成树中任意顶点之间有且仅有一条通路,也就是说,生成树中不能存在回路;

  • 对于具有 n 个顶点的连通网,其生成树中只能有 n-1 条边,这 n-1 条边连通着 n 个顶点。

  • 连接 n 个顶点在不产生回路的情况下,只需要 n-1 条边。

  • 所以克鲁斯卡尔算法的具体思路是:将所有边按照权值的大小进行升序排序,然后从小到大一一判断,条件为:如果这个边不会与之前选择的所有边组成回路,就可以作为最小生成树的一部分;反之,舍去。直到具有 n 个顶点的连通网筛选出来 n-1 条边为止。筛选出来的边和所有的顶点构成此连通网的最小生成树。

  • 判断是否会产生回路的方法为:在初始状态下给每个顶点赋予不同的标记,对于遍历过程的每条边,其都有两个顶点,判断这两个顶点的标记是否一致,如果一致,说明它们本身就处在一棵树中,如果继续连接就会产生回路;如果不一致,说明它们之间还没有任何关系,可以连接。

  • 假设遍历到一条由顶点 A 和 B 构成的边,而顶点 A 和顶点 B 标记不同,此时不仅需要将顶点 A 的标记更新为顶点 B 的标记,还需要更改所有和顶点 A 标记相同的顶点的标记,全部改为顶点 B 的标记。

  • (6)


  • 当选取的边的数量相比与顶点的数量小 1 时,说明最小生成树已经生成。所以最终采用克鲁斯卡尔算法得到的最小生成树为(6)所示。


  • 实现代码:#include "stdio.h"#include "stdlib.h"#define MAX_VERtEX_NUM 20#define VertexType inttypedef struct edge{VertexType initial;VertexType end;VertexType weight;}edge[MAX_VERtEX_NUM];//定义辅助数组typedef struct {VertexType value;//顶点数据int sign;//每个顶点所属的集合}assist[MAX_VERtEX_NUM];assist assists;//qsort排序函数中使用,使edges结构体中的边按照权值大小升序排序int cmp(const void *a,const void*b){return ((struct edge*)a)->weight-((struct edge*)b)->weight;}//初始化连通网void CreateUDN(edge *edges,int *vexnum,int *arcnum){printf("输入连通网的边数: ");scanf("%d %d",&(*vexnum),&(*arcnum));printf("输入连通网的顶点: ");for (int i=0; i<(*vexnum); i++) {scanf("%d",&(assists[i].value));assists[i].sign=i;}printf("输入各边的起始点和终点及权重: ");for (int i=0 ; i<(*arcnum); i++) {scanf("%d,%d,%d",&(*edges)[i].initial,&(*edges)[i].end,&(*edges)[i].weight);}}//在assists数组中找到顶点point对应的位置下标int Locatevex(int vexnum,int point){for (int i=0; i<vexnum; i++) {if (assists[i].value==point) {return i;}}return -1;}int main(){int arcnum,vexnum;edge edges;CreateUDN(&edges,&vexnum,&arcnum);//对连通网中的所有边进行升序排序,结果仍保存在edges数组中qsort(edges, arcnum, sizeof(edges[0]), cmp);//创建一个空的结构体数组,用于存放最小生成树edge minTree;//设置一个用于记录最小生成树中边的数量的常量int num=0;//遍历所有的边for (int i=0; i<arcnum; i++) {//找到边的起始顶点和结束顶点在数组assists中的位置int initial=Locatevex(vexnum, edges[i].initial);int end=Locatevex(vexnum, edges[i].end);//如果顶点位置存在且顶点的标记不同,说明不在一个集合中,不会产生回路if (initial!=-1&& end!=-1&&assists[initial].sign!=assists[end].sign) {//记录该边,作为最小生成树的组成部分minTree[num]=edges[i];//计数+1num++;//将新加入生成树的顶点标记全不更改为一样的for (int k=0; k<vexnum; k++) {if (assists[k].sign==assists[end].sign) {assists[k].sign=assists[initial].sign;}}//如果选择的边的数量和顶点数相差1,证明最小生成树已经形成,退出循环if (num==vexnum-1) {break;}}}//输出语句for (int i=0; i<vexnum-1; i++) {printf("%d,%d ",minTree[i].initial,minTree[i].end);}return 0;}

  • 测试数据:

  • 输入连通网的边数:
    6 10
    输入连通网的顶点:
    1
    2
    3
    4
    5
    6
    输入各边的起始点和终点及权重:
    1,2,6
    1,3,1
    1,4,5
    2,3,5
    2,5,3
    3,4,5
    3,5,6
    3,6,4
    4,6,2
    5,6,6
    1,3
    4,6
    2,5
    3,6
    2,3

⑵ 克鲁斯卡尔算法

哈哈,因为爱情。
parent数组装的是每个连通分量的第一个开始点,最初的状态有n个节点,n个分量,都是第一个,所以全都赋值0,而开始合并后,将一个个的分量逐步的合并到一起,parent记录的就是父节点,一个联通分量只有一个parent为0的。
而判断循环是如果两个的最终的开始节点是同一个,就说明你加上这条边就形成循环了,这条边就不能加

⑶ 克鲁斯卡尔算法的算法描述

克鲁斯卡尔算法的时间复杂度为O(eloge)(e为网中边的数目),因此它相对于普里姆算法而言,适合于求边稀疏的网的最小生成树。
克鲁斯卡尔算法从另一途径求网的最小生成树。假设连通网N=(V,{E}),则令最小生成树的初始状态为只有n个顶点而无边的非连通图T=(V,{∮}),图中每个顶点自成一个连通分量。在E中选择代价最小的边,若该边依附的顶点落在T中不同的连通分量上,则将此边加入到T中,否则舍去此边而选择下一条代价最小的边。依次类推,直至T中所有顶点都在同一连通分量上为止。
例如图为依照克鲁斯卡尔算法构造一棵最小生成树的过程。代价分别为1,2,3,4的四条边由于满足上述条件,则先后被加入到T中,代价为5的两条边(1,4)和(3,4)被舍去。因为它们依附的两顶点在同一连通分量上,它们若加入T中,则会使T中产生回路,而下一条代价(=5)最小的边(2,3)联结两个连通分量,则可加入T。因此,构造成一棵最小生成树。
上述算法至多对 e条边各扫描一次,假若以“堆”来存放网中的边,则每次选择最小代价的边仅需O(loge)的时间(第一次需O(e))。又生成树T的每个连通分量可看成是一个等价类,则构造T加入新的过程类似于求等价类的过程,由此可以以“树与等价类”中介绍的 mfsettp类型来描述T,使构造T的过程仅需用O(eloge)的时间,由此,克鲁斯卡尔算法的时间复杂度为O(eloge)。

⑷ 克鲁斯卡尔算法的时间复杂度为多少

时间复杂度为O(|E|log|E|),其中E和V分别是图的边集和点集。

基本思想是先构造一个只含 n 个顶点、而边集为空的子图,把子图中各个顶点看成各棵树上的根结点,之后,从网的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图,即把两棵树合成一棵树。

反之,若该条边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之。依次类推,直到森林中只有一棵树,也即子图中含有 n-1 条边为止。

(4)克鲁斯卡尔算法扩展阅读:

克鲁斯卡尔算法证明

假设G=(V,E) 是一个具有n个顶点的连通网,T=(U,TE)是G的最小生成树,U的初值等于V,即包含有G中的全部顶点,TE的初值为空集。该算法的基本思想是:将图G中的边按权值从小到大的顺序依次选取。

若选取的边使生成树T不形成回路,则把它并入TE中,保留作为T的一条边,若选取的边使生成树T形成回路,则将其舍弃,如此进行下去直到TE中包含n-1条边为止,此时的T即为最小生成树。

克鲁斯卡尔算法,至多对e条边各扫描一次,每次选择最小代价的边仅需要O(loge)的时间。因此,克鲁斯卡尔算法的时间复杂度为O(eloge)。

⑸ 如何实现克鲁斯卡尔算法

最好结合具体题目实现,我这里有个题目,里面有完整的代码,慢慢理解就是了 http://blog.csdn.net/aihahaheihei/article/details/6751786
里面还有很多,感兴趣也可以看看

⑹ kruskal算法

给每个子树一个不同的编号,对每一个顶点引入一个标记t,表示这个顶点所在的子树编号。当加入一条红色边,就会使该边两端点所在的两个子树连接起来,成为一个子树,从而两个子树中的顶点标记要改变成一样。综上,可将Kruskal算法细化使其更容易计算机实现。

kruskal应该是递归算法吧,在定义图中各端点时,可以多设一个标记,把图递归遍历一遍,在同一连同子图上的点,标记为一样的整型数值即可。

参考:http://ke..com/view/580403.htm

⑺ 克鲁斯卡尔算法的基本思想

先构造一个只含 n 个顶点、而边集为空的子图,把子图中各个顶点看成各棵树上的根结点,之后,从网的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图,即把两棵树合成一棵树,反之,若该条边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之。依次类推,直到森林中只有一棵树,也即子图中含有 n-1 条边为止。时间复杂度为为O(e^2), 使用并查集优化后复杂度为 O(eloge),与网中的边数有关,适用于求边稀疏的网的最小生成树。

⑻ 克鲁斯卡尔算法 判断回路中的问题

看这段代码真令我头疼,我就告诉你思路吧!
并查集你会不会?如果会的话那就好办。
kruskal算法用到了一种贪心策略,首先要把边集数组以边的权值从小到大排序,然后一条边一条边的查找,如果边的两个端点不在一个集合内,则将此边添加到正在生长的树林中,并合并两个端点所在的集合,直到最小生成树已生成完毕。
核心伪代码如下(本人不习惯给完整的可编译的代码):
func root(x:longint):longint;//查找i节点所在集合
var i,j,k:longint;
{i:=x;j:=x;
while i!=f[i] do i=f[i];
while j!=i do
{k=j;j=f[j];f[k]=i;}//路径压缩,若不压缩效率将很低
};//root
proc union(i,j,c:longint);
var x,y:longint;
{x=root(i);
y=root(j);
if x!=y then {inc(ans,c);inc(temp);f[y]=x;}
//若i和j分属两棵子树,则将此边添加到森林中,并合并其所在集合
};//union;
将边集数组按照边的权值从小到大排序;
for (i=1,i++,i=n) f[i]=i;//并查集初始化
for (i=1,i++,i=m)
{union(edge[i].x,edge[i].y,edge[i].z);
if temp==n-1 then break;
//若temp==n-1则最小生成树已生成完毕,退出
}//kruskal
if temp==n-1 then writeln(ans)//输出最小生成树的权值和
else writeln('No solution!');//若temp!=n-1,则说明此图为非连通图

热点内容
共享云源码 发布:2024-09-08 10:01:10 浏览:394
ios应用上传 发布:2024-09-08 09:39:41 浏览:439
ios储存密码哪里看 发布:2024-09-08 09:30:02 浏览:873
opensslcmake编译 发布:2024-09-08 09:08:48 浏览:653
linux下ntp服务器搭建 发布:2024-09-08 08:26:46 浏览:744
db2新建数据库 发布:2024-09-08 08:10:19 浏览:173
频率计源码 发布:2024-09-08 07:40:26 浏览:780
奥迪a6哪个配置带后排加热 发布:2024-09-08 07:06:32 浏览:101
linux修改apache端口 发布:2024-09-08 07:05:49 浏览:209
有多少个不同的密码子 发布:2024-09-08 07:00:46 浏览:566