数据结构基础6.3:最小生成树MST(Prim、Kruskal)

本文介绍了图论中的最小生成树概念及其两种主要算法:Prim算法和Kruskal算法。Prim算法适用于边数较多的情况,通过迭代选择权重最小的边来构建最小生成树;Kruskal算法适用于边数较少的情况,通过排序并按顺序添加不构成环的边来构建最小生成树。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.最小生成树(MST):

连通图的一次遍历所经过的边的集合及图中所有顶点的集合就构成了该图的一棵生成树,对连通图的不同遍历,就可以得到不同的生成树。

如果无向连通图就是一个网,那么,它的所有生成树中必有一棵边的权值总和最小的生成树,我们称这棵生成树为最小生成树。


二.最小生成树的两种算法:

1.Prim算法:

适用范围:该算法针对顶点展开,适用于边数较多的情况。

算法描述:

1).输入:一个加权连通图,其中顶点集合为V,边集合为E;

2).初始化:Vnew = {x},其中x为集合V中的任一节点(起始点),Enew = {},为空;

3).重复下列操作,直到Vnew = V:

a.在集合E中选取权值最小的边<u, v>,其中u为集合Vnew中的元素,而v不在Vnew集合当中,并且v∈V(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一);

b.将v加入集合Vnew中,将<u, v>边加入集合Enew中;

4).输出:使用集合Vnew和Enew来描述所得到的最小生成树。

代码实现:

/* 最小连通网Prim算法 */
Status Prim(MGraph graph, Vertex n)
{
    int i, j, min = INF, index;
    bool marked[MaxVertexSize];
    int P[MaxVertexSize];
    int cost[MaxVertexSize];
    
    if(n < 0 || n >= graph->Nv)
        return ERROR;
        
    for(i = 0; i < graph->Nv; i++) {
        marked[i] = false;
        cost[i] = graph->matrix[n][i];
        P[i] = n;
    }
    marked[n] = true;
    
    for(i = 0; i < graph->Nv - 1; i++) {
        min = INF;
        
        for(j = 0; j < graph->Nv; j++) {
            if(!marked[j] && cost[j] < min) {
                min = cost[j];
                index = j;
            }
        }

        printf("%d, %d, %d\n", P[index], index, min);
        marked[index] = true;
        printf("%d\n", graph->Nv);
        
        for(j = 0; j < graph->Nv; j++) {
            if(!marked[j] && graph->matrix[index][j] < cost[j]) {
                cost[j] = graph->matrix[index][j];
                P[j] = index;
            }
        }
    }
    
    return OK;
}

2.Krukal算法:

适用范围:该算法针对边展开,适用于边数较少的情况。

算法描述:

1).记Graph中有v个顶点,e个边

2).新建图Graphnew,Graphnew中拥有原图中相同的e个顶点,但没有边

3).将原图Graph中所有e个边按权值从小到大排序

4).循环:从权值最小的边开始遍历每条边 直至图Graph中所有的节点都在同一个连通分量中

    如果这条边连接的两个节点于图Graphnew中不在同一个连通分量中,添加这条边到图Graphnew中。

代码实现:

typedef struct KrusEdge {
    Vertex a,b;
    WeightType weight;
} KrusEdge;

/* 冒泡排序 */
Status sort(KrusEdge s[], int n)
{
    bool flag;
    int i, j;
    KrusEdge temp;
    
    if(!s)
        return ERROR;
    for(i = 0; i < n - 1; i++) {
        for(j = i + 1; j < n; j++) {
            if(s[j].weight < s[i].weight) {
                temp = s[j];
                s[j] = s[i];
                s[i] = temp;
            }
        }
    }
    
    return OK;    
}

/* 最小连通网Kruskal算法 */
Status Kruskal(MGraph graph)
{
    int i, j, k = 0, s1, s2;
    int vsrc[MaxVertexSize];
    KrusEdge edge[MaxEdgeNum];
    
    if(!graph)
        return ERROR;
        
    for(i = 0; i < graph->Nv; i++)
        for(j = 0; j < graph->Nv; j++) {
            if(graph->matrix[i][j] != 0 && graph->matrix[i][j] != INF) {
                edge[k++] = {i, j, graph->matrix[i][j]};
            }
        }
    for(i = 0; i < graph->Nv; i++)
        vsrc[i] = i; 
        
    sort(edge, k);
    
    k = 0;
    i = 1;
    while(i < graph->Nv) {
        s1 = vsrc[edge[k].a];
        s2 = vsrc[edge[k].b];
        if(s1 != s2) {
            printf("%d, %d, %d\n", edge[k].a, edge[k].b, edge[k].weight);
            
            for(j = 0; j < graph->Nv; j++) {
                if(vsrc[j] == s2)
                    vsrc[j] = s1;
            }
            i++;
        }
        k++;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值