最小(代价)生成树-克鲁斯卡尔算法(Kruskal)

2020-02-04  本文已影响0人  Jorunk

克鲁斯卡尔算法是一种用来寻找最小生成树的算法。在剩下的所有未选取的边中,找最小边,如果和已选取的边构成回路,则放弃,选取次小边。这同样是一个比较难以理解的算法,这一次我又是看了别人的博客才理解了一点。

1.将图的所有连接线去掉,只剩顶点

2.从图的边集数组中找到权值最小的边,将边的两个顶点连接起来

3.继续寻找权值最小的边,将两个顶点之间连接起来,如果选择的边使得最小生成树出现了环路,则放弃该边,选择权值次小的边

4.直到所有的顶点都被连接在一起并且没有环路,最小生成树就生成了。


解释代码

for (int i = 0; i < G->numvertex; i++)
    {
        parent[i] = 0;  //初始化全部为0,
    }

        n = Find(parent, edges[i].begin);   // 4 2 0 1 5 3 8 6 6 6 7
        m = Find(parent, edges[i].end);     // 7 8 1 5 8 7 6 6 6 7 7
        
        if( n != m )        // 如果n==m,则形成环路,不满足!
        {
            parent[n] = m;  // 将此边的结尾顶点放入下标为起点的parent数组中,表示此顶点已经在生成树集合中
            printf("(%d, %d) %d ", edges[i].begin, edges[i].end, edges[i].weight);
        }
int Find(int *parent, int f)
{
    while( parent[f] > 0 )
    {
        f = parent[f];
    }
    
    return f;
}

0.(4,7)这条边判断是否有环,代码如下:


顶点4连到顶点7

  1. 边(2,8)


2.边(0,1)



parent[0]=0,parent[1]=0;与上面情况一样,放心大胆修吧,n=0,m=1,更新地图parent[0]=1,意味着从0出发能走到1.


3.边(0,5)



4.边(1,8)


7.边(5,6)


我们从2出发,paerent[2]=8,来到8,parent[8]=6,来到6,parent[6]=0,到达6终止,修路会出现环路,所以不修

9.边(6,7)


完整代码

#include<stdio.h>
 
#define MAXEDGE 100
#define MAXVERTEX 100
typedef struct Edge
{
    int begin;//边的起点
    int end;  //边的终点
    int wight;//边的权值
}Edge;
 
typedef struct Graph
{
    char vertex[MAXVERTEX];//顶点
    Edge edges[MAXEDGE];//边
    int numvertex,numedges;//顶点和边的个数
}MGraph;
 
void CreateGraph(MGraph* G)
{
    printf("请输入顶点和边的个数:\n");
    scanf("%d%d", &G->numvertex, &G->numedges);
    printf("请输入顶点:\n");
    getchar();//利用该函数除去上一系我们在输入结束时按得回车符
    for (int i = 0; i < G->numvertex; i++)
    {
        scanf("%c", &G->vertex[i]);
    }
    printf("按权值从小到大输入边(vi,vj)对应的起点和终点的下标,begin,end以及权值wight:\n");
    for (int k = 0; k < G->numedges; k++)
    {
        Edge e;
        scanf("%d%d%d", &e.begin, &e.end, &e.wight);
        G->edges[k] = e;
    }
}
 
int Find(int *parent, int f)
{
    while (parent[f]>0)
    {
        f = parent[f];
    }
    return f;
}
 
//最小生成树,克鲁斯卡尔算法
void Kruskal(MGraph *G)
{
    
    int parent[MAXVERTEX];//存放最小生成树的顶点
    for (int i = 0; i < G->numvertex; i++)
    {
        parent[i] = 0;
    }
    int m, n;
    for (int i = 0; i < G->numedges; i++)
    {
        n = Find(parent, G->edges[i].begin);
        m = Find(parent, G->edges[i].end);
        if (n != m)//m=n说明有环
        {
            parent[n] = m;
            printf("(%d,%d) %d\t", G->edges[i].begin, G->edges[i].end, G->edges[i].wight);//打印边和权值
        }
    }
}
 
int main()
{
    MGraph G;
    CreateGraph(&G);
    Kruskal(&G);
    
    return 0;
}

对于上面的那张图最后输出 (4,7)7,(2,8)8,(0,1)10,(0,5)11,(1,8)12,(3,7)16,(1,6)16,(6,7)19

上一篇 下一篇

猜你喜欢

热点阅读