Kruskal算法构造最小生成树

  1. 问题[描述算法问题,首选形式化方式(数学语言),其次才是非形式化方式(日常语言)]
    在一给定的无向图G = (V, E) 中,(u, v) 代表连接顶点 u 与顶点 v 的边(即),而 w(u, v) 代表此边的权重,若存在 T 为 E 的子集(即)且为无向循环图,使得的 sum(w(u, v))最小,则此 T 为 G 的最小生成树。
  2. 解析[问题的理解和推导,可用电子版直接在此编写,也可用纸笔推导,拍照嵌入本文档]
    在这里插入图片描述
  3. 设计[核心伪代码]
    首先运用快排把边按升序分别排列好,然后再开始KRUSKAL函数
    void kruskal(Edge E[],int n,int e){ 定义一个初始数组 k表示当前最小生成树边的总数 j表示E里边的下标,默认初值为0 当生成的边数小于总边长的时候继续循环 { m1=E[j].vex1; m2=E[j].vex2;//取一条边的两个邻接点 sn1=vset[m1]; sn2=vset[m2]; //分别得到两个顶点所属的集合编号 if(sn1!=sn2)//两顶点分属于不同的集合,该边是最小生成树的一条边 { 输出两个顶点和所在边 总和相加 生成的最小生成树边数增加1 如果边有达到最大的数量 退出循环 for(i=1;i<=n;i++) 两个集合统一起来集合编号修改 } 继续下一条边 } 最后输出总和} 4. 分析[算法复杂度推导]时间复杂度:nlogn kruskal算法用于变数较少的稀疏图
    源码[github源码地址]
    #include <stdio.h>
    typedef struct{ int vex1; //边起始顶点
    int vex2; //边终止顶点 int weight; //边权值}Edge;void kruskal(Edge E[],int n,int e){ int i,j,m1,m2,sn1,sn2,k,sum=0; int vset[n+1]; for(i=1;i<=n;i++) //初始化数组 vset[i]=i; k=1;//表示当前最小生成树边的总数 j=0;//E里边的下标,默认初值为0 while(k<e)//生成的边数小于总边长的时候继续循环 { m1=E[j].vex1; m2=E[j].vex2;//取一条边的两个邻接点 sn1=vset[m1]; sn2=vset[m2]; //分别得到两个顶点所属的集合编号 if(sn1!=sn2)//两顶点分属于不同的集合,该边是最小生成树的一条边 {//防止出现闭合回路 printf(“V%d-V%d=%d\n”,m1,m2,E[j].weight); sum+=E[j].weight;//总和相加 k++; //生成的最小生成树边数增加 if(k>=n) break; for(i=1;i<=n;i++) //两个集合统一编号 if (vset[i]==sn2) //集合编号为sn2的改为sn1 vset[i]=sn1; } j++; //扫描下一条边 } printf("%d\n",sum);}int fun(Edge arr[],int low,int high) { int key; Edge lowx; lowx=arr[low]; key=arr[low].weight; while(low<high) { while(low<high && arr[high].weight>=key) high–; if(low<high) arr[low++]=arr[high]; while(low<high && arr[low].weight<=key) low++; if(low<high) arr[high–]=arr[low]; } arr[low]=lowx; return low; } void quick_sort(Edge arr[],int start,int end){ int pos; if(start<end) { pos=fun(arr,start,end); quick_sort(arr,start,pos-1); quick_sort(arr,pos+1,end); }}int main(){ Edge E[1000000]; int nume,numn; scanf("%d%d",&numn,&nume); for(int i=0;i<nume;i++) scanf("%d%d%d",&E[i].vex1,&E[i].vex2,&E[i].weight); quick_sort(E,0,nume-1); kruskal(E,numn,nume);}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值