普利姆(Prim)算法是以某个顶点为起点,逐步寻找各个顶点上权值最小的边来构建生成树。
文章指引:图—普里姆(Prim)算法(原理和C程序解释)
而克鲁斯卡尔(Kruskal)算法是以边为目标,直接寻找权值最小的边来构建生成树,并在构建中不形成回路。

一、定义

假设N = (V, {E})是一个连通网,则令最小生成树的初始状态为只有n个顶点而无边的非连通图T = {V, {}},图中每个顶点自成一个连通分量。
在E中选择代价最小的边,若该边依附的顶点落在T中不同的连通分量上,则将此边加入到T中,否则舍去此边而选择下一条代价最小的边。依次类推,直至T中所有顶点都在同一连通分量上为止。


二、实现思路

下图是一个连通网,我们以此来介绍普利姆算法的实现过程。


(1)首先设立最小生成树的初始状态T = {V, {}},只有顶点,没有边,寻找权值最小的边,显然是(v1,v5)(v_1,v_5)(v1​,v5​)最小。

注:红色边为最小生成树的边,黑色线为连通网的边。

(2)然后(v1,v7)(v_1,v_7)(v1​,v7​)边权值最小

(3)此时有两条边的权值均为8,这里先取(v0,v1)(v_0,v_1)(v0​,v1​)边

(4)添加(v4,v5)(v_4,v_5)(v4​,v5​)边

(5)添加(v3,v7)(v_3,v_7)(v3​,v7​)边

(6)因为(v2,v3)(v_2,v_3)(v2​,v3​)边的两个顶点在同一连通分量中,如果添加此边,则会形成回路,所以添加(v0,v5)(v_0,v_5)(v0​,v5​)边

(7)添加(v4,v6)(v_4,v_6)(v4​,v6​)边

(8)添加(v5,v8)(v_5,v_8)(v5​,v8​)边

此时所有顶点都在同一连通分量上,红色边所有顶点构造的树即为最小生成树。


三、程序解析

1. 临接矩阵转换为边集数组

(1)因为无向图的邻接矩阵是对称矩阵,那么边集数组只需要统计矩阵的右上半即可。edge[]用于存储图的每一条边。

(2)对边安装权值排序,由大到小,这里使用比较简单的冒泡排序法。

//邻接矩阵转边集数组,按照权值排序,由小到大
void MGraph2EdgeArr(MGraph G, Edge* edge)
{int i, j, k=0;Edge temp;//将边数据填入edge中for (i = 0; i < G.numVertexes; i++){for (j = i + 1; j < G.numVertexes; j++){if (G.arc[i][j] != INFINITY)    //有边{edge[k].begin = i;edge[k].end = j;edge[k].weight = G.arc[i][j];k++;}}}//冒泡排序for (i = 0; i < k; i++){for (j = i+1; j < k; j++){if (edge[j].weight < edge[i].weight){temp = edge[i];edge[i] = edge[j];edge[j] = temp;}}}
}

2. 克鲁斯卡尔算法程序

(1)parent数组:将同一连通分量的顶点串起来,下标为edge.begin,即各边的尾顶点下标,parent存储的值是边的头顶点下标,如果某一个顶点是两个边的尾,则在上一个边的头顶点位置存储下一个边的头顶点下标

比如最小生成树依次添加了(v1,v2)(v_1,v_2)(v1​,v2​),(v1,v7)(v_1,v_7)(v1​,v7​),(v0,v1)(v_0,v_1)(v0​,v1​),此时parent发生如下变化:

在添加(v1,v7)(v_1,v_7)(v1​,v7​)关系时,因为parent[1]=2parent[1] = 2parent[1]=2,parent[2]=0parent[2] = 0parent[2]=0,因此使parent[2]=7parent[2] = 7parent[2]=7。

如何判断两个顶点是否在同一连通分量呢?

可以根据parent观察,因为parent[0]=7,parent[7]=0parent[0] = 7,\ parent[7] = 0parent[0]=7, parent[7]=0,所以v0,v7v_0, v_7v0​,v7​在同一分量中,取名为连通分量A;因为parent[1]=2,parent[2]=7parent[1] = 2, \ parent[2] = 7parent[1]=2, parent[2]=7,所以v1,v2,v7v_1, v_2, v_7v1​,v2​,v7​,它们均在连通分量A中。

我们只需要判断连线顶点的结尾顶点是否相同,如v1,v2v_1,v_2v1​,v2​连线均以v7v_7v7​为结尾。

(2)按照权值从小到大遍历所有边,Find函数查找边的两端顶点所在的连通分量的结尾顶点,如果不同,则认为可以将此边添加到最小生成树中,不存在回路,打印该边信息。更新parent信息,将两个顶点所在的连通分量连接起来。

typedef struct // 边集结构
{int begin;int end;int weight;
}Edge;
#define MAXEDGE (15) //最大边数void MiniSpanTree_Kruskal(MGraph G)
{int i, n, m;Edge edges[MAXEDGE]; //定义边集数组int parent[MAXEDGE]; //定义一数组用来判断边与边是否形成环路MGraph2EdgeArr(G, edges); //将邻接矩阵转换为边集数组for (i = 0; i < G.numEdges; i++){parent[i] = 0; //初始化数组值为0}for (i = 0; i < G.numEdges; i++){n = Find(parent, edges[i].begin);m = Find(parent, edges[i].end);if (n != m) //判断edges[i].begin和edges[i].end是否在同一连通分量中{parent[n] = m; //将edges[i].begin与edges[i].end连线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;
}

3. 测试

#include "CreateGraph.h"
#include "kruskal.h"int main()
{MGraph G;CreateMgraph(&G);MiniSpanTree_Kruskal(G);return 0;
}

打印输出:


四、总结

因为Find函数的时间复杂度为O(loge)O(loge)O(loge),e为连通网的边数,且for循环e次,则卡鲁斯卡尔的时间复杂度为O(eloge)O(eloge)O(eloge)。该算法主要针对边来展开,因此对于边数少的连通网来说,效率比较高。

【数据结构】图—克鲁斯卡尔算法(原理及C程序详解)相关推荐

  1. 数据结构——图——克鲁斯卡尔(Kruskal)算法

    数据结构--图--克鲁斯卡尔(Kruskal)算法 同样的思路,我们也可以直接就以边为目标去构建,因为权值是在边上,直接去找最小权值的边来构建生成树也是很自然的想法,只不过构建时要考虑是否会形成环路而 ...

  2. 克鲁斯卡尔算法原理及JAVA代码

    原理 视频 最小生成树(Kruskal(克鲁斯卡尔)和Prim(普里姆))算法动画演示_哔哩哔哩_bilibili 文章 聊一聊数据结构图的克鲁斯卡尔算法 - 简书 (jianshu.com) 根据前 ...

  3. 【网格图软判决译码】基于比特级的MAP译码(Bitwise MAP Decoding)算法原理推导和例题详解(intrinsic和extrinsic值)

    Bitwise MAP Decoding算法详解 C C C表示一个(n,k)码,生成矩阵为 G G G,编码如下 Encoding u =

  4. 【MATLAB】混合粒子群算法原理、代码及详解

    目录 1.算法 1.1.原理 1.2.性能比较 1.3.步骤 2.代码 2.1.源码及注释 2.2.执行与效果 1.算法 1.1.原理 \qquad建议没接触过粒子群算法的朋友先看较为基础的全局粒子群 ...

  5. Canny边缘检测算法原理及其VC实现详解(一)

    原文地址:http://blog.csdn.net/likezhaobin/article/details/6892176 图象的边缘是指图象局部区域亮度变化显著的部分,该区域的灰度剖面一般可以看作是 ...

  6. Java语言求笛卡尔积,Java笛卡尔积算法原理与实现方法详解

    本文实例讲述了Java笛卡尔积算法原理与实现方法.分享给大家供大家参考,具体如下: 笛卡尔积算法的Java实现: (1)循环内,每次只有一列向下移一个单元格,就是CounterIndex指向的那列. ...

  7. Apriori 算法原理以及python实现详解

    Apriori 算法原理以及python实现 ​ Apriori算法是第一个关联规则挖掘算法,也是最经典的算法.它利用逐层搜索的迭代方法找出数据库中项集的关系,以形成规则,其过程由连接(类矩阵运算)与 ...

  8. java 笛卡尔积_Java笛卡尔积算法原理与实现方法详解

    本文实例讲述了Java笛卡尔积算法原理与实现方法.分享给大家供大家参考,具体如下: 笛卡尔积算法的Java实现: (1)循环内,每次只有一列向下移一个单元格,就是CounterIndex指向的那列. ...

  9. RRT与RRT*算法具体步骤与程序详解(python)

    提示:前面写了A*.Dijkstra算法 文章目录 前言 一.RRT的原理与步骤 二.RRT算法编写的步骤 1.算法步骤 2.算法的实现 三.RRT*算法编写的步骤 1.算法的步骤 2.算法的实现 三 ...

最新文章

  1. vue vuex vue-router后台项目——权限路由(超详细简单版)
  2. Java 实现第三方 QQ 账号登录
  3. jvm内存配置参数_性能测试连载 (23)jvm内存参数设置
  4. 十个问题理解Linux epoll工作原理
  5. 2017-2018 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2017)
  6. SQL预编译防注入小测试
  7. 【计算机系统设计】实践笔记(3)改进数据通路:移位R型指令分析
  8. 深入解读 Knative Eventing 0.7 版本新特性
  9. 世上最简单的mysql_史上最简单安装MySQL教程
  10. 精密制造业行业_精密制造业行业前景(全球精密制造业排名)
  11. android 多平台发布,内容多平台发布
  12. 关于web页面中mata各种标签的解释
  13. java编写一个方法printn_Java语言程序设计 基础篇 原书第10版 ,梁勇著 (第六章)编程练习题...
  14. DM - Manager工具
  15. python图像文字识别 - PyTesser
  16. 移动硬盘损坏怎么恢复?找到原因再解决
  17. 计算机上怎么计算x的n次方,计算x的n次方(用函数)
  18. tipask二次开发总结_tipask二次开发总结
  19. f文件服务器,f文件服务器
  20. addon游戏_MOD Simple Shader addon

热门文章

  1. Hive---外部表和内部表
  2. hp小型机日常设备维护检查
  3. sortable的基本属性
  4. zzulioj1147: 查找子数组
  5. iOS 字体适配的几种方法总结
  6. promethesu普罗米修斯安装
  7. python 正则表达式 re 爬取网页及分析总结
  8. 人生思考--碌碌无为的一天
  9. 【转】配置Symbian模拟器支持模拟MMC存储卡
  10. 学习笔记2014/4/15