【数据结构与算法】最小生成树之普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法

这篇具有很好参考价值的文章主要介绍了【数据结构与算法】最小生成树之普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【数据结构与算法】最小生成树之普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法 

🌱博客主页:大寄一场.

🌱系列专栏:数据结构与算法

😘博客制作不易欢迎各位👍点赞+⭐收藏+➕关注
【数据结构与算法】最小生成树之普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法

【数据结构与算法】最小生成树之普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法

目录

前言

一、最小生成树的概念

二、最小生成树的求解方法

三、练习题

四、最小生成树在实际应用中的例子


前言

最近非科班的同学学到了最小生成树并询问我,于是想趁热打火,来总结顺便复习一下~

最小生成树(Minimum Spanning Tree,简称MST)是一个无向连通图中包含所有顶点的最短边集。在许多实际问题中,找到一个最小生成树对于理解和解决这些问题至关重要。本文将介绍最小生成树的概念、求解方法以及其在实际应用中的一些例子。

一、最小生成树的概念

假设我们有一个无向连通图G=(V,E),其中V是顶点集合,E是边集合。我们需要找到一个最小生成树,使得每个顶点都至少与一条边相连。这个最小生成树就是MST。

【数据结构与算法】最小生成树之普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法 

 

二、最小生成树的求解方法

1.Prim算法 Prim算法是一种贪心算法,用于在具有有向边的加权图中寻找最小生成树。算法的基本思想是从任意一个顶点开始,沿着权重最小的边进行扩展,直到找到整个MST


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define INF INT_MAX

// 邻接矩阵表示的无向图
typedef struct {
    int V; // 顶点数
    int E; // 边数
    int G[100][100]; // 邻接矩阵
} Graph;

// 获取边的权重
int getWeight(Graph G, int u, int v) {
    return G[u][v];
}

// Kruskal算法求最小生成树
Graph primMST(Graph G) {
    int V = G.V; // 顶点数
    int E = G.E; // 边数
    int parent[V]; // 父节点数组
    int dist[V]; // 从源点到每个顶点的距离数组
    int i, u, v;
    int minCost = 0; // 总代价
    int edgeCount = 0; // 已选边的数量
    Graph mstEdges; // MST边集合
    memset(parent, -1, sizeof(parent)); // 初始化父节点为-1
    memset(dist, INF, sizeof(dist)); // 初始化距离为正无穷大
    priorityQueueNode pq; // 优先队列头结点
    pq.data = (void*)&dist[0];
    pq.index = 0;
    memset(mstEdges.G, 0, sizeof(mstEdges.G)); // 将邻接矩阵清零
    mstEdges.V = V;
    mstEdges.E = 0;
    do { // 不断扩展最小生成树,直到不存在增广路为止
        u = pq.index; // 取出距离源点最近的顶点u
        if (u == -1) break; // 如果已经没有顶点可选了,跳出循环
        pq.index = parent[u]; // 将当前顶点更新为其父节点
        edgeCount++; // 已选边的数量加1
        for (i = 0; i < G.V; i++) { // 遍历所有顶点
            v = i; // 从当前顶点开始选择下一个顶点v
            if (dist[v] > dist[u] + G.G[u][v]) { // 如果从u到v的距离比从u到源点的距离更短,则更新距离和优先级队列头结点
                dist[v] = dist[u] + G.G[u][v];
                pq.data = (void*)&dist[0];
                pq.index = i;
            } else if (i != u && v != u) { // 如果当前顶点u不是目标顶点,且从u到v的距离比从u到源点的距离更短,则将边的权重加入到最小生成树中,并更新优先级队列头结点的位置
                mstEdges.G[edgeCount] = getWeight(G, u, v);
                pq.data = (void*)&mstEdges.G[0];
                pq.index = edgeCount++;
            } else if (i == u && v != u) { // 如果当前顶点u是目标顶点,但从u到v的距离比从u到源点的距离更短,则将边的权重加入到最小生成树中,并将当前顶点更新为其父节点的值为已选边的数量减一(因为此时已经找到了一条增广路径)
                mstEdges.G[edgeCount] = getWeight(G, u, v);
                parent[v] = edgeCount--; // 将当前顶点的父节点设为已选边的数量减一(因为此时已经找到了一条增广路径)
            } else if (i != u && v == u) continue; // 如果当前顶点u是目标顶点且从u到v的距离等于从u到源点的距离,则不需要进行任何操作,直接跳过本次循环继续下一次循环迭代
        }
        minCost += mstEdges.G[mstEdges.E-1]; // 将总代价加上已选边的权重之和作为新的总代价
        mstEdges.E++; // 将已选边的计数加一,表示又选了一条边加入到最小生成树中
    } while (edgeCount < V); // 当已选边的数量小于顶点数时,继续扩展最小生成树直到不存在增广路为止

2.Kruskal算法 Kruskal算法也是一种贪心算法,用于在具有有向边的加权图中寻找最小生成树。算法的基本思想是每次选择权重最小的边来将两个顶点连接起来,直到找到整个MST。


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define INF INT_MAX

// 邻接矩阵表示的无向图
typedef struct {
    int V; // 顶点数
    int E; // 边数
    int G[100][100]; // 邻接矩阵
} Graph;

// 获取边的权重
int getWeight(Graph G, int u, int v) {
    return G[u][v];
}

// Kruskal算法求最小生成树
Graph primMST(Graph G) {
    int V = G.V; // 顶点数
    int E = G.E; // 边数
    int parent[V]; // 父节点数组
    int dist[V]; // 从源点到每个顶点的距离数组
    int i, u, v;
    int minCost = 0; // 总代价
    int edgeCount = 0; // 已选边的数量
    Graph mstEdges; // MST边集合
    memset(parent, -1, sizeof(parent)); // 初始化父节点为-1
    memset(dist, INF, sizeof(dist)); // 初始化距离为正无穷大
    priorityQueueNode pq; // 优先队列头结点
    pq.data = (void*)&dist[0];
    pq.index = 0;
    memset(mstEdges.G, 0, sizeof(mstEdges.G)); // 将邻接矩阵清零
    mstEdges.V = V;
    mstEdges.E = 0;
    do { // 不断扩展最小生成树,直到不存在增广路为止
        u = pq.index; // 取出距离源点最近的顶点u
        if (u == -1) break; // 如果已经没有顶点可选了,跳出循环
        pq.index = parent[u]; // 将当前顶点更新为其父节点
        edgeCount++; // 已选边的数量加1
        for (i = 0; i < G.V; i++) { // 遍历所有顶点
            v = i; // 从当前顶点开始选择下一个顶点v
            if (dist[v] > dist[u] + G.G[u][v]) { // 如果从u到v的距离比从u到源点的距离更短,则更新距离和优先级队列头结点
                dist[v] = dist[u] + G.G[u][v];
                pq.data = (void*)&dist[0];
                pq.index = i;
            } else if (i != u && v != u) { // 如果当前顶点u不是目标顶点,且从u到v的距离比从u到源点的距离更短,则将边的权重加入到最小生成树中,并更新优先级队列头结点的位置
                mstEdges.G[edgeCount] = getWeight(G, u, v);
                pq.data = (void*)&mstEdges.G[0];
                pq.index = edgeCount++;
            } else if (i == u && v != u) { // 如果当前顶点u是目标顶点,但从u到v的距离比从u到源点的距离更短,则将边的权重加入到最小生成树中,并将当前顶点更新为其父节点的值为已选边的数量减一(因为此时已经找到了一条增广路径)
                mstEdges.G[edgeCount] = getWeight(G, u, v);
                parent[v] = edgeCount--; // 将当前顶点的父节点设为已选边的数量减一(因为此时已经找到了一条增广路径)
            } else if (i != u && v == u) continue; // 如果当前顶点u是目标顶点且从u到v的距离等于从u到源点的距离,则不需要进行任何操作,直接跳过本次循环继续下一次循环迭代
        }
        minCost += mstEdges.G[mstEdges.E-1]; // 将总代价加上已选边的权重之和作为新的总代价
        mstEdges.E++; // 将已选边的计数加一,表示又选了一条边加入到最小生成树中
    } while (edgeCount < V); // 当已选边的数量小于顶点数时,继续扩展最小生成树直到不存在增广路为止

三、练习题

对如图所示的带权连通图按照克鲁斯卡尔和普里姆算法得到其最小生成树,请写出生成过程中依次得到的各条边,并计算该最小生成树的权值。

【数据结构与算法】最小生成树之普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法

 普里姆算法从任意一个顶点开始,沿着权重最小的边进行扩展

【数据结构与算法】最小生成树之普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法

克鲁斯卡尔 每次选择权重最小的边来将两个顶点连接起来

【数据结构与算法】最小生成树之普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法

四、最小生成树在实际应用中的例子

最小生成树在很多实际应用中有很广泛的应用,例如路由算法、社交网络分析、电路设计等。下面分别介绍这些领域中的应用案例。

  1. 路由算法
    最小生成树在路由算法中有很重要的应用。例如,在单源最短路径问题中,我们可以使用Prim算法或Kruskal算法来找到最小生成树。同时,最小生成树也可以用于计算网络中每个节点的最短路径。这对于网络优化和资源分配非常重要。

  2. 社交网络分析
    最小生成树在社交网络分析中也有很广泛的应用。例如,我们可以使用最小生成树来确定社交网络中的社区结构。通过将每个节点与它的邻居节点连接起来,并删除具有较小的连通性(即具有较少的邻居节点)的边,我们可以得到一个最小生成树。然后,我们可以通过检查哪些节点之间的边被保留来确定这些节点属于同一个社区。

  3. 电路设计
    最小生成树在电路设计中有很重要的应用。例如,在电路布线中,我们可以使用最小生成树来最小化电路的总长度和电阻。通过将电路中的节点与它们的相邻节点连接起来,并删除具有较小的阻抗(即具有较少的电阻或电容)的边,我们可以得到一个最小生成树。然后,我们可以选择将电阻和电容分配给这个最小生成树上的节点,以最小化总长度和阻抗。

总之,最小生成树在许多领域中都有着广泛的应用。它不仅可以帮助我们解决各种计算问题,还可以帮助我们理解和分析现实世界中的复杂系统。


【数据结构与算法】最小生成树之普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法文章来源地址https://www.toymoban.com/news/detail-466155.html

到了这里,关于【数据结构与算法】最小生成树之普里姆(Prim)算法和克鲁斯卡尔(Kruskal)算法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 大话数据结构-普里姆算法(Prim)和克鲁斯卡尔算法(Kruskal)

       构造连通网的最小代价生成树称为最小生成树,即Minimum Cost Spanning Tree ,最小生成树通常是基于无向网/有向网构造的。   找连通网的最小生成树,经典的有两种算法,普里姆算法和克鲁斯卡尔算法。   普里姆算法,即Prim算法,大致实现过程如下:   (1) 新建数组

    2024年02月05日
    浏览(29)
  • 最小生成树(详解普里姆算法)

    首先,我们来看一下 图的一些基本知识点 : 图 :图 G=(V,E) 由顶点集 V 和边集 E 组成。每条边对应一个点对 (v,w),其中 v,w 属于 V 。如果图中的点对是有序的,那么该图就是有向图,反之为无向图。 邻接点 :若顶点 v 与 w 之间存在一条边,则认为顶点 v 与 w 邻接。 权 :图

    2024年01月19日
    浏览(63)
  • 0302Prim算法-最小生成树-图-数据结构和算法(Java)

    1.1 概述 1.1.1 算法描述 算法描述: 初始化最小生成树,只有一个起点; 每次将下一条连接树中顶点和其补集中顶点且权重最小的边(黑色表示)加入树中; 重复步骤中2,直至最小生成树中加入了V-1条边。 命题L。Prim算法能够得到任意加权连通图的最小生成树。 证明:有命

    2023年04月16日
    浏览(26)
  • 数据结构与算法课程设计---最小生成树的应用

    1.问题 假定有这么一个问题,有11个城市,城市之间有一些天然气管道,铺设天然气管道需要花费不同的金额,现在要你选择其中一些天然气管道,使得所有城市可以互相联通且花费最小。 2.分析 我们把这个问题抽象为一张图,每个城市是一个顶点,城市与城市之间的管道是

    2024年02月08日
    浏览(26)
  • 【数据结构与算法】图的搜索——广度优先遍历、最小生成树

    邻接链表: 用字典实现.有向图的邻接链表的总长度等于图的边个数;无向图的邻接链表的总长度等于图的边个数的2倍. 邻接矩阵:用于最短路径算法. 该数据结构维护一个不相交动态集的集合,每个集合有一个代表,不关心谁做代表。 支持三种操作: MAKE_SET(x) FIND_SET(x) UNION(x,y

    2024年02月19日
    浏览(22)
  • C++数据结构——习题6-5 最小生成树(Prim算法)

    省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。已知村庄数N和可建道路数M,设初始状态下任意村庄之间没有路,请编写程序,根据输入的两村庄间修建道路的费用情况,计算这些村庄

    2024年02月09日
    浏览(60)
  • 【数据结构】无向图的最小生成树(Prime,Kruskal算法)

    连通图 :在 无向图 中,若从顶点v1到顶点v2有路径,则称顶点v1与顶点v2是连通的。如果图中 任意一对顶点都是连通的 ,则称此图为连通图 强连通图 :在 有向图 中,若在每一对顶点vi和vj之间都存在一条从vi到vj的路径,也存在一条从vj到vi的路径,则称此图是强连通图 生成

    2024年01月24日
    浏览(22)
  • 求最小生成树Prim(普里姆)和Kruskal(克鲁斯卡尔)算法

     想求最小生成树,我们首先得弄懂以下几个概念   连通图 :图中任意两个顶点都是连通的 极小连通子图 :既要保持图连通又要使得边数最少的子图 生成树 : 包含图中全部顶点的一个极小连通子图 连通图用通俗的话来讲就是,某一个顶点,可以 直接或者间接 (通过其他顶点

    2024年02月05日
    浏览(22)
  • 已知无向图G如下所示,使用普里姆 (Prim)算法求图G的最小生成树。 (a)请写出从顶点T出发,加到最小生成树中的边次序。 (6分) (2)说明Prim算法更适用于求哪种类型无向图的最小生 成树。(2分) (3)当图中顶点个数为n,边的个数为e时,该算法

    (a)从顶点T出发,加到最小生成树中的边次序如下: 先加入顶点T到顶点E的边,得到的最小生成树为:T-E 再加入顶点E到顶点D的边,得到的最小生成树为:T-E-D 再加入顶点D到顶点B的边,得到的最小生成树为:T-E-D-B 再加入顶点B到顶点C的边,得到的最小生成树为:T-E-D-B-C 再加

    2024年01月17日
    浏览(28)
  • 【数据结构】二叉树之链式结构

    🔥 博客主页 : 小羊失眠啦. 🎥 系列专栏 : 《C语言》 《数据结构》 《Linux》 《Cpolar》 ❤️ 感谢大家点赞👍收藏⭐评论✍️ 在学习二叉树各种各样的操作前,我们先来回顾一下二叉树的概念: 二叉树是度不超过2的树,由根结点和左右2个子树组成,每个子树也可以看作

    2024年02月04日
    浏览(20)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包