Kruskal算法构造最小生成树

生成树:包含全部顶点的一个极小连通子图

最小生成树:代价(权值和)最小的生成树


算法:Kruskal算法

输入:无向连通网G=(V,E)

输出:最小生成树T=(U,TE)        

1. 初始化:U=V;TE={ }

2. 重复下述操作直到所有顶点位于一个连通分量中         

3.在E中选取最短边(u,v),

  • 如果顶点 u、v 位于两个连通分量,则将边 (u,v) 并入TE,并将这两个连通分量合成一个连通分量
  • 如果顶点 u、v 位于一个连通分量,在 E 中标记边 (u,v),使得 (u,v) 不参加后续最短边的选取

图的存储结构:边集数组

合并连通分量:并查集

并查集:集合中的元素组织成树的形式:

(1)查找两个元素是否属于同一集合:所在树的根结点是否相同

(2)合并两个集合:将一个集合的根结点作为另一个集合根结点的孩子


#include <iostream>

using namespace std;
struct EdgeType{//边集数组
    int from,to,weight;//起点,终点,权值
};
class EdgeGraph{
public:
    EdgeGraph(char a[],int n,int e);
    ~EdgeGraph();
    void Kruskal();
    int FindRoot(int parent[],int v);//求顶点v所在集合的根
private:
    char vertex[10];
    EdgeType edge[100];
    int vertexNum,edgeNum;
};

EdgeGraph::EdgeGraph(char a[],int n,int e){
    int i,j,k,w;
    vertexNum=n;edgeNum=e;
    for(i=0;i<vertexNum;i++)
        vertex[i]=a[i];
    for(k=0;k<edgeNum;k++){
        cout<<"请输入边的两个顶点编号和边的权值:";
        cin>>i>>j>>w;
        edge[k].from=i;edge[k].to=j;edge[k].weight=w;
    }
}
EdgeGraph::~EdgeGraph(){}

void EdgeGraph::Kruskal(){
    int num=0,i,vex1,vex2;
    int parent[vertexNum];//双亲表示法存储并查集
    for(i=0;i<vertexNum;i++)
        parent[i]=-1;//初始化没有双亲,置-1
    for(num=0,i=0;num<vertexNum-1;i++){//在已排好序的边集数组中找最短边
        vex1=FindRoot(parent,edge[i].from);
        vex2=FindRoot(parent,edge[i].to);
        if(vex1!=vex2){//分属两个集合
            cout<<"("<<edge[i].from<<","<<edge[i].to<<")"<<" "<<edge[i].weight<<endl;
            parent[vex2]=vex1;//合并集合
            num++;
        }
    }
}

EdgeGraph::FindRoot(int parent[],int v){
    int t=v;
    while(parent[t]>-1)
        t=parent[t];//求顶点t的双亲一直到根
    return t;
}

//(1 4 12)(2 3 17)(0 5 19) (2 5 25)(3 5 25)(4 5 26)(0 1 34)(3 4 38)(0 2 46) 
int main()
{
    char ch[6]={'A','B','C','D','E','F'};
    EdgeGraph eg(ch,6,9);
    eg.Kruskal();
    return 0;
}
运行结果
请输入边的两个顶点编号和边的权值:1 4 12
请输入边的两个顶点编号和边的权值:2 3 17
请输入边的两个顶点编号和边的权值:0 5 19
请输入边的两个顶点编号和边的权值:2 5 25
请输入边的两个顶点编号和边的权值:3 5 25
请输入边的两个顶点编号和边的权值:4 5 26
请输入边的两个顶点编号和边的权值:0 1 34
请输入边的两个顶点编号和边的权值:3 4 38
请输入边的两个顶点编号和边的权值:0 2 46
(1,4) 12
(2,3) 17
(0,5) 19
(2,5) 25
(4,5) 26

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Kruskal算法是一种常用的构造最小生成树算法,其基本思想是从小到大选择边,直到选出n-1条边为止。下面是C语言实现Kruskal算法构造最小生成树的代码: ```c #include <stdio.h> #include <stdlib.h> #define MAX_VERTICES 1000 #define MAX_EDGES 10000 typedef struct edge { int u, v, w; } Edge; int parent[MAX_VERTICES]; int rank[MAX_VERTICES]; Edge edges[MAX_EDGES]; Edge mst[MAX_EDGES]; int num_vertices, num_edges; void make_set(int x) { parent[x] = x; rank[x] = 0; } int find_set(int x) { if (x != parent[x]) { parent[x] = find_set(parent[x]); } return parent[x]; } void union_set(int x, int y) { int px = find_set(x); int py = find_set(y); if (rank[px] > rank[py]) { parent[py] = px; } else { parent[px] = py; if (rank[px] == rank[py]) { rank[py]++; } } } int compare(const void *a, const void *b) { Edge *ea = (Edge *) a; Edge *eb = (Edge *) b; return ea->w - eb->w; } void kruskal() { int i, j = 0; for (i = 0; i < num_vertices; i++) { make_set(i); } qsort(edges, num_edges, sizeof(Edge), compare); for (i = 0; i < num_edges && j < num_vertices - 1; i++) { Edge e = edges[i]; int u = e.u; int v = e.v; if (find_set(u) != find_set(v)) { union_set(u, v); mst[j++] = e; } } } int main() { int i; scanf("%d %d", &num_vertices, &num_edges); for (i = 0; i < num_edges; i++) { scanf("%d %d %d", &edges[i].u, &edges[i].v, &edges[i].w); } kruskal(); printf("Minimum Spanning Tree:\n"); for (i = 0; i < num_vertices - 1; i++) { printf("%d %d %d\n", mst[i].u, mst[i].v, mst[i].w); } return 0; } ``` 在这个实现中,我们使用了一个Edge结构体来表示边,其中包括起点、终点和边权。我们使用了并查集来判断是否形成环,使用了快速排序算法对所有边按照边权从小到大排序。最后,我们输出构造出的最小生成树

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值