前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >最小生成树——Prim算法与Kruskal算法

最小生成树——Prim算法与Kruskal算法

作者头像
mindtechnist
发布于 2024-08-08 09:15:32
发布于 2024-08-08 09:15:32
14300
代码可运行
举报
文章被收录于专栏:机器和智能机器和智能
运行总次数:0
代码可运行

最小生成树概念:连通图: 在一个无向图中,任意两个顶点之间都是可达的(有路径连通),则成该无向图为连通图。生成树: 一个连通图的生成树是一个极小的连通子图,它含有图中的全部顶点,但只有构成一棵树的n-1条边。也就是说,无向图中连通n个顶点n-1条边就叫做生成树。最小生成树: 构造连通图的最小代价生成树称为最小生成树,也就是说,所有的边加权后和最小的树。

Prim算法

Prim算法计算最小生成树的方法从一个结点开始使树一点点的成长。在每一步,都增加一个结点作为根,并连接这个结点作为边,也就是说每次增加一个一个结点和一条边,这样也就把相关联的顶点加到增长中的树上了。这个过程主要体现在“加点”,在算法进行的过程中,有一个已经添加到树上的顶点集,这个顶点集实际就是最小生成树的结点集合,其余顶点都作为选择,等待是否被加入集合。每次选择一个顶点,使得它和上一个顶点之间的代价最小,并把这条边加入到最小生成树中,把顶点加入到集合中。下面通过图示来描述Prim算法的思想:首先选择一个顶点作为起始,比如A,第一轮发现AC代价最小,那么就把AC边加入最小生成树,把A加入顶点集合;

后面依次寻找最小代价边,直到全部顶点都加入到顶点集合。

在程序中,通过一个最小代价标记,并一行一行的扫描来搜索最小代价边,下面来看具体代码。首先我们定义一个图的数据类型,该数据类型包含图的顶点集合、邻接矩阵,顶点数和边数。另外宏定义两个常量,通过一个不可能的数比如65535来表示两个顶点之间没有边。

代码语言:javascript
代码运行次数:0
运行
复制
#define MAXVER      6       /*最大顶点个数*/
#define INFINITY    65535   /*代表无穷大*/

typedef struct _graph_type
{
    char    vertex[MAXVER]; /*存放顶点的数组*/
    int     arc[MAXVER][MAXVER]; /*邻接矩阵*/ 
    int     vertex_num; /*顶点数*/
    int     edge_num; /*边数*/
}graph_type;

Prim算法C语言实现

代码语言:javascript
代码运行次数:0
运行
复制
/*普利姆Prim算法求最小生成树*/
void mini_span_tree_prim(graph_type g)
{
    int min = 0; /*保存最小权值*/
    int k = 0; /*存放最小权值的顶点下标*/
    int i = 0;
    int j = 0;
    int vertex_tree[MAXVER]; /*顶点下标 - 最小生成树的结点*/
    int weight[MAXVER]; /*边的权值,置为0表示下标对应的顶点已加入最小生成树*/
    
    weight[0] = 0; /*假设图标号为0的顶点是最小生成树的第一个结点*/
    vertex_tree[0] = 0; /*加入第一个顶点*/
    
    for(i = 1; i < g.vertex_num; i++) /*遍历图的所有顶点*/
    {
        weight[i] = g.arc[0][i]; /*把和0号顶点有边的边的权值存入数组*/
        vertex_tree[i] = 0; /*初始化为0号顶点*/
    }
    
    for(i = 1; i < g.vertex_num; i++)
    {
        min = INFINITY; /*初始化最小权值为无穷大*/
        j = 1;
        k = 0;
        while(j < g.vertex_num) /*遍历所有顶点*/
        {
            if(weight[j] != 0 && weight[j] < min)
            {
                /*如果权值不为0(未加入最小生成树),且权值小于最小权值min*/
                min = weight[j]; /*更新当前最小权值*/
                k = j; /*保存最小权值边所以来的顶点,第一次循环表示 (0, k)为0开始的所有边中权值最小的边*/
            }
            j++;
        }
        weight[k] = 0; /*将k的权值置为0,表示这个结点的最小权值已经找到了,同时顶点k已被加入最小生成树中*/
        for(j = 1; j < vertex_num; j++)
        {
            if(weight[j] != 0 && g.arc[k][j] < weight[j])
            {
                /*如果j没有加入最小生成树,且邻接矩阵第k行相应权值小于weigh记录的最小权值*/
                weight[j] = g.arc[k][j]; /*更新weight*/
                vertex_tree[j] = k; /*把k加入到最小生成树*/
            }
        }
    }
}

Kruskal算法

Prim算法是以某个顶点开始,逐步寻找各个顶点上最小权值的边,这样一步步来构建最小生成树。第二种贪心策略是连续地按照最小的权选择边,并且当所选的边不产生回路时就把它作为取定的边。在形式上Kruskal算法是在处理一个森林,开始的时候,存在n棵单结点的树,每次添加一条边把两棵树合并成一棵树,当算法终止时剩下的一棵树就是最小生成树。假设图和上面一样

首先我们得到一张表,每条边按权值从小到大排序

然后开始加边,优先选择权值小的边

加最后一条边,得到最小生成树,和Prim算法得到的一样

Kruskal算法C语言实现

代码语言:javascript
代码运行次数:0
运行
复制
#define MAXedge_type 20 /*最大边数*/
#define MAXVEX 20  /*最大顶点数*/
#define INFINITY 65535 /*无穷大*/

typedef struct
{
    int arc[MAXVEX][MAXVEX];
    int vertex_num;
    int edge_type_num;
}graph_type;

typedef struct
{
    int begin;
    int end;
    int weight;
}edge_type;   /* 对边集数组edge_type结构的定义 */

/* 交换权值 以及头和尾 */
void Swapn(edge_type *edge_types,int i, int j)
{
    int temp;
    temp = edge_types[i].begin;
    edge_types[i].begin = edge_types[j].begin;
    edge_types[j].begin = temp;
    temp = edge_types[i].end;
    edge_types[i].end = edge_types[j].end;
    edge_types[j].end = temp;
    temp = edge_types[i].weight;
    edge_types[i].weight = edge_types[j].weight;
    edge_types[j].weight = temp;
}

/* 对权值进行排序 */
void sort(edge_type edge_types[], graph_type *G)
{
    int i, j;
    for ( i = 0; i < G->edge_type_num; i++)
    {
        for ( j = i + 1; j < G->edge_type_num; j++)
        {
            if (edge_types[i].weight > edge_types[j].weight)
            {
                Swapn(edge_types, i, j);
            }
        }
    }
    printf("权排序之后的为:\n");
    for (i = 0; i < G->edge_type_num; i++)
    {
        printf("(%d, %d) %d\n", edge_types[i].begin, edge_types[i].end, edge_types[i].weight);
    }

}

/* 查找连线顶点的尾部下标 */
int Find(int *parent, int f)
{
    while ( parent[f] > 0)
    {
        f = parent[f];
    }
    return f;
}

/* 生成最小生成树 */
void MiniSpanTree_Kruskal(graph_type G)
{
    int i, j, n, m;
    int k = 0;
    int parent[MAXVEX];/* 定义一数组用来判断边与边是否形成环路 */
    
    edge_type edge_types[MAXedge_type];/* 定义边集数组,edge_type的结构为begin,end,weight,均为整型 */

    /* 用来构建边集数组并排序 */
    for ( i = 0; i < G.vertex_num-1; i++)
    {
        for (j = i + 1; j < G.vertex_num; j++)
        {
            if (G.arc[i][j]<INFINITY)
            {
                edge_types[k].begin = i;
                edge_types[k].end = j;
                edge_types[k].weight = G.arc[i][j];
                k++;
            }
        }
    }
    sort(edge_types, &G);

    for (i = 0; i < G.vertex_num; i++)
        parent[i] = 0;  /* 初始化数组值为0 */

    for (i = 0; i < G.edge_type_num; i++)   /* 遍历每一条边 */
    {
        n = Find(parent,edge_types[i].begin);
        m = Find(parent,edge_types[i].end);
        if (n != m) /* 假如n与m不等,说明此边没有与现有的生成树形成环路 */
        {
            parent[n] = m;  /* 将此边的结尾顶点放入下标为起点的parent中。 */
                            /* 表示此顶点已经在生成树集合中 */
            printf("(%d, %d) %d\n", edge_types[i].begin, edge_types[i].end, edge_types[i].weight);
        }
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-04-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 机器和智能 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
【商业数据分析】用户价值RFM模型详解
一个聪明的营销者懂得“了解你的客户”的重要性。营销人员不能仅关注于产生更多的点击量,他们必须遵循从增加点击率到保持、忠诚和建立客户关系的模式转变。 与其把整个客户群作为一个整体来分析,不如把他们分成同质化的群体,了解每个群体的特点,让他们参与相关的活动,而不是仅仅根据客户的年龄或地理位置来细分。 接下来介绍的RFM模型是最受欢迎的、易于使用的和有效的客户细分方法之一,它使市场营销人员能够分析客户行为。
润森
2022/09/22
3.2K0
【商业数据分析】用户价值RFM模型详解
构建RFM体系:优化客户分析和营销策略
RFM 分析是一种用于洞悉客户价值和行为的强大工具,广泛应用于市场营销和客户关系管理。本文将介绍 RFM 分析如何在数据产品不充分的情况下实现以及如何利用RFM分析来优化营销策略,提高客户满意度,增加业务收益。
政采云前端团队
2023/09/22
1.8K0
构建RFM体系:优化客户分析和营销策略
数字化运营:如何进行用户分层,将钱花在刀刃上?
在产品初期,当用户量比较少,原始粗犷的运营方式可以满足日常产品的需求。但随着产品逐步扩张,用户量也逐步增加,互联网流量红利的时代逐渐结束,粗暴的方式难以继续,多样化的用户需要精细化的运营。这个时候数字化精细化运营的价值将得到体现,提升效率,降低运营成本,把钱花在刀刃上。数字化运营包含有很多种如用户分层、用户分群、用户画像等多种方式。本篇主要介绍用户分层。
产品言语
2022/06/02
4870
数字化运营:如何进行用户分层,将钱花在刀刃上?
腾讯大数据沙龙(北京站):赋能运营,助力增长!
5月26日,腾讯大数据2018年线下沙龙-北京站在798艺术区举行。现场集结了互联网圈数十家知名企业的运营增长官和负责产品推广的小伙伴,通过五小时的思维碰撞,共同打造这场由大数据赋能带来的知识盛宴。
腾讯大数据
2018/06/11
9420
如何成为数据型产品经理
产品经理的概念在不断泛化。近些年来,随着互联网行业的发展,越来越多的企业意识到了大数据和精细化运营的重要性,为了更好地挖掘数据的价值,指导业务的优化和发展,数据产品经理应运而生,他们基于数据分析方法发现问题,并提炼关键要素,设计产品来实现商业价值。这篇文章主要是对数据型产品经理进行拆解细分,探寻在AAA教育学习有哪些细节。
张哥编程
2024/12/19
1250
如何成为数据型产品经理
数仓:如何使用RFM模型进行用户分层?
在适当、有效的商务智能环境中,数据分析的质量必须得到保障。而确保数据分析质量的第一步就是根据问题需求从海量数据中提炼出真正所需的数据,因为这是发挥数据价值很重要的一个方面。通过数据的分析与可视化呈现可以更加直观的提供数据背后的秘密,从而辅助业务决策,实现真正的数据赋能业务。本文主要介绍在用户分层和用户标签中常常使用的一个模型——RFM模型。
Python数据科学
2021/09/08
1.9K0
数仓:如何使用RFM模型进行用户分层?
案例实操|手把手教你搭建 RFM 客户价值分析模型
随着电商的不断发展,网上购物变得越来越流行。更多电商平台崛起,对于电商卖家来说增加的不只是人们越来越高的需求,还要面对更多强大的竞争对手。面对这些挑战,就需要能够及时发现店铺经营中的问题,并且能够有效解决这些实际的问题,从而提升自身的竞争力。
用户6888863
2023/03/01
1.4K0
案例实操|手把手教你搭建 RFM 客户价值分析模型
不知道如何衡量会员的价值?来学习下RFM模型
很多直接面向消费者的企业,也是我们常说的To C的企业通常都会建立自己的会员体系,并在线上和线下的渠道中积累了大量的会员数据。但是如何能够更好的利用这些会员数据以及如何识别哪些是高价值的会员,这些都是每个企业都在不断探索的话题。 我们今天就一起来讨论一个可行的方案,RFM模型。讨论的内容主要会分为两个部分:
臭豆腐
2019/04/16
1.4K0
不知道如何衡量会员的价值?来学习下RFM模型
用户运营指标体系建设实践
企业的生存和发展的根本是用户,用户的规模和增速可以决定一个公司的生死存亡。所以,各行各业,不管在做什么业务,都绕不开对用户的运营。今天主要讲讲,对于电商行业,用户运营主要做什么,如何构建数据化驱动的用户运营指标体系。
数据干饭人
2022/07/01
5950
用户运营指标体系建设实践
电商如何进行精细化运营?
背景:在互联网及移动设备不断普及的时代背景下,越来越多的国内传统品牌商及国际知名品牌为提高销售规模纷纷试水电商业务。基于电商市场的持续扩增以及品牌商电商化的业务需求,众多企业通过向品牌方提供金融支付、品牌运营、整合营销、 IT 服务、物流仓储、供应链等服务而得到快速发展,电商服务产业因此而不断壮大,消费者消费习惯也因此改变。
1480
2019/08/05
2.2K0
电商如何进行精细化运营?
营销4.0时代,数据、技术如何驱动品牌营销增长?
在互联网迅猛发展的大背景下,PC端、手机端的流量增长、转移,消费者的阅读习惯、行为路径以及接收信息的渠道和方式等等都发生了巨变。与此同时,科技的进步也引领着整个行业与社会进步,催生新的商业生态,并迸发出新的火花。
盈鱼MA
2019/12/24
1.6K0
营销4.0时代,数据、技术如何驱动品牌营销增长?
用户增长常见分析模型
用户增长基本上会涉及生意场上的各行各业,你开个店面希望有更多的客户光顾,你做了个APP希望有更多的用户经常使用,你搭建了个电商平台希望有更多的人下单买东西。
Spark学习技巧
2023/10/07
1.1K0
用户增长常见分析模型
RFM会员价值度模型
会员价值度用来评估用户的价值情况,是区分会员价值的重要模型和参考依据,也是衡量不同营销效果的关键指标。
@小森
2024/03/15
5320
RFM会员价值度模型
【补贴策略】用户质量&用户价值&用户成本的ROI提升
导 语 腾讯灯塔 用户增长三要素——“用户成本、用户质量、用户价值”之间的效率ROI的提升,是帮助供给侧和用户端的“交易效率的提升"和"市场占有率的提升"的重要抓手。 写在前面 增长的策略分析 产品护城河:每个赛道都有蓝海到红海的阶段,尤其当所有行业进行升级,美团(餐饮升级)、滴滴(打车升级)、抖音(视频升级)、小红书(决策升级)等等。当红海过后,资本退缩、行业下滑,市场进入寒冬,我们要何去何从?从“降本增效、精耕细作”入手,在技术壁垒、算法壁垒、供给侧运营能力壁垒中,依然看到了可以更好提升的有力抓手。
腾讯灯塔小明
2022/08/25
2.8K0
【补贴策略】用户质量&用户价值&用户成本的ROI提升
使用pyspark实现RFM模型及应用(超详细)
本文主要介绍了RFM模型,以及使用pyspark实现利用RFM模型对用户分层的简单应用~让大家对RFM有一个更深刻的认识
languageX
2023/07/03
8320
一文理解增长黑客方法论
| 导语 网上讲增长黑客方法论的文章很多,但大多只是碎片化的知识点或者雷同内容的复制粘贴,无法形成系统性的知识框架。 我读了增长黑客的3本书,浏览了100多篇文章,结合营销的专业知识梳理出增长黑客最核心的方法论,实战用到哪个部分的内容可以继续用关键词检索学习。 鹅厂越来越多的业务组建了增长团队,同时也利用增长黑客的方法低成本高效率地促进用户增长。数据化运营、数据驱动决策、精益数据分析等相关概念也非常火热。那么,你了解增长黑客吗? 本文将梳理增长黑客理论发展至今的核心方法论,与大家一起学习和讨论。
腾讯大讲堂
2019/08/20
2.4K0
一文理解增长黑客方法论
几何级增长的客户:客户深度运营的13个关键数据模型
宋星是数据化互联网营销与运营资深的从业者和行业意见领袖,“互联网分析在中国”博客(原“网站分析在中国”)全文作者,新南威尔士大学营销分析行业顾问委员会(UNSW Marketing Analytics Advisory Board)委员。阳狮媒体集团特聘顾问,百度集团顾问与钻石讲师,腾讯星河计划顾问,Google mLab顾问,北京航空航天大学特聘教授,前阳狮媒体集团数据、技术与创新事业部总经理,前Adobe Omniture Business Unit亚太区首席商业咨询顾问。
iCDO互联网数据官
2019/07/31
1.3K0
大数据【企业级360°全方位用户画像】之RFM模型和KMeans聚类算法
在上一篇博客《一文带你硬核踏入机器学习的大门》中,已经为大家介绍了很多关于机器学习的基础内容。本篇博客,我们将结合当前阶段正在做的用户画像项目,为大家介绍RFM模型和KMeans聚类算法。
大数据梦想家
2021/01/27
1.5K0
大数据【企业级360°全方位用户画像】之RFM模型和KMeans聚类算法
用户增长——CLV用户生命周期价值CLTV 笔记(一)
目前该系列的几篇: 用户增长——CLV用户生命周期价值CLTV 笔记(一) 用户增长 - BG/NBD概率模型预测用户生命周期LTV(二) 用户增长——Cohort Analysis 留存分析(三)
悟乙己
2021/12/07
3.7K0
用户增长——CLV用户生命周期价值CLTV 笔记(一)
【数据分析】客户细分
何为客户细分?是技术,更是艺术 客户细分是20世纪50年代中期由美国学者温德尔史密斯提出的,其理论依据在于顾客需求的异质性和企业需要在有限资源的基础上进行有效地市场竞争.是指企业在明确的战略业务模式和特定的市场中,根据客户的属性,行为,需求,偏好以及价值等因素对客户进行分类,并提供有针对性的产品,服务和销售模式.按照客户的外在属性分层,通常这种分层最简单直观,数据也很容易得到. 其实各个行业、各个角色都在不同的时期来划分不同的人群,有的性别划分(男and女),有的根据用户的粘性划分(活跃and沉默),但遇到
陆勤_数据人网
2018/02/27
2.4K0
推荐阅读
相关推荐
【商业数据分析】用户价值RFM模型详解
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档