最小生成树之kruskal算法(附代码)

prim算法是通过找距离最近的节点来扩充最小生成树的,稠密图选择prim算法效率比较高,但是对于稀疏图呢,prim算法就显的比较鸡肋了。对于稀疏图,有一个叫做kruskal的算法。此算法求稀疏图的效率比较高,时间复杂度为O(ElogE)。

kruskal算法主要通过找最小的边来合并节点来一步步的生成树的,他一开始将每个节点看成一棵树,然后通过边的关系来进行节点的合并,这里需要对给出的边进行升序排序,然后再检查边所联系的两个节点是否在同一集合,如果不在同一集合则将两个集合合并,直到整个森林变为一颗树为止。

代码如下:
 

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
const int maxn=1005;
int n,m;
struct edge
{
    int s,e;
    int len;
};
edge e[maxn];
int a[maxn];
vector <edge> ve; //记录纳入的边
//初始化
int init ()
{
    for (int i=1;i<=n;i++)
        a[i]=i;
}
//查找父节点
int finds(int re)
{
    if(re==a[re])
        return re;
    return a[re]=finds(a[re]);
}
//将两个集合联合
bool unit (int x,int y)
{
    int temp1=finds(x);
    int temp2=finds(y);
    if(temp1!=temp2)
    {
         a[temp1]=temp2;
         return true;
    }
    return false;
}
int compare (edge a,edge b)
{
    return a.len<b.len;
}
//krusal算法
int kruskal ()
{
    //先进行排序
    sort(e,e+m,compare);
    int num=n;
    int sum=0;
    for (int i=0;i<m&&num>1;i++)
    {
        //判断是否在同一集合中,在同一集合就不再计入
        if(unit(e[i].s,e[i].e))
        {
            ve.push_back(e[i]);
            sum+=e[i].len;
            num--;
        }
    }
    if(num==1)
        printf("最小生成树的权值和为%d\n",sum);
    else
        printf("不存在最小生成树\n");
}
//遍历纳入的边
void traverse ()
{
    printf("纳入的边为:\n");
    for (int i=0;i<ve.size();i++)
        printf("%d<->%d 长度为%d\n",ve[i].s,ve[i].e,ve[i].len);
}
int main()
{
    scanf("%d%d",&n,&m);
    init();
    for (int i=0;i<m;i++)
    {
        scanf("%d%d%d",&e[i].s,&e[i].e,&e[i].len);
    }
    kruskal();
    traverse ();
    return 0;
}
/*运行结果
6 15
1 2 5
1 3 3
1 4 7
1 5 4
1 6 2
2 3 4
2 4 6
2 5 2
2 6 6
3 4 6
3 5 1
3 6 1
4 5 10
4 6 8
5 6 3
最小生成树的权值和为12
纳入的边为:
3<->5 长度为1
3<->6 长度为1
1<->6 长度为2
2<->5 长度为2
2<->4 长度为6*/

 

  • 17
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是用C语言实现Kruskal算法代码,该算法可以生成一棵最小生成树: ``` #include <stdio.h> #include <stdlib.h> #define MAX_EDGE_NUM 1000 #define MAX_VERTEX_NUM 100 // 定义边的结构体 typedef struct { int u, v; // 两个顶点 int w; // 权值 } Edge; // 定义并查集结构体 typedef struct { int parent[MAX_VERTEX_NUM]; // 每个顶点的父节点 int rank[MAX_VERTEX_NUM]; // 每个顶点的秩 } UnionFindSet; // 初始化并查集 void makeSet(UnionFindSet* set, int n) { for (int i = 0; i < n; i++) { set->parent[i] = i; set->rank[i] = 0; } } // 查找节点x所在集合的根节点 int find(UnionFindSet* set, int x) { if (set->parent[x] != x) { set->parent[x] = find(set, set->parent[x]); } return set->parent[x]; } // 合并两个节点所在的集合 void unionSet(UnionFindSet* set, int x, int y) { int rootX = find(set, x); int rootY = find(set, y); if (rootX != rootY) { if (set->rank[rootX] > set->rank[rootY]) { set->parent[rootY] = rootX; } else if (set->rank[rootX] < set->rank[rootY]) { set->parent[rootX] = rootY; } else { set->parent[rootY] = rootX; set->rank[rootX]++; } } } // Kruskal算法 void kruskal(Edge* edges, int n, int m) { UnionFindSet set; makeSet(&set, n); Edge result[MAX_VERTEX_NUM]; int count = 0; int i = 0; while (count < n - 1) { Edge e = edges[i++]; int u = e.u; int v = e.v; int w = e.w; if (find(&set, u) != find(&set, v)) { result[count++] = e; unionSet(&set, u, v); } } for (int i = 0; i < count; i++) { printf("(%d, %d) %d\n", result[i].u, result[i].v, result[i].w); } } // 测试 int main() { int n, m; scanf("%d%d", &n, &m); Edge edges[MAX_EDGE_NUM]; for (int i = 0; i < m; i++) { scanf("%d%d%d", &edges[i].u, &edges[i].v, &edges[i].w); } kruskal(edges, n, m); return 0; } ``` 其中,makeSet函数用于初始化并查集;find函数用于查找节点所在的集合的根节点;unionSet函数用于合并两个节点所在的集合。kruskal函数是Kruskal算法的实现,它先将所有边按权值从
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值