最小生成树——Kruskal(克鲁斯卡尔)算法

【0】README

0.1) 本文总结于 数据结构与算法分析, 源代码均为原创, 旨在 理解 Kruskal(克鲁斯卡尔)算法 的idea 并用 源代码加以实现;
0.2)最小生成树的基础知识,参见 http://blog.csdn.net/pacosonswjtu/article/details/49947085


【1】 Kruskal 算法(使用到了不相交集ADT的union/find 操作)

1.1)第二种贪婪策略是: 连续地按照最小的权选择边, 并且当所选的边不产生圈时就可以吧它作为取定的边;
1.2)形式上, Kruskal算法是在处理一个森林——树的集合。 开始的时候, 存在 |V|颗单节点树, 而添加一边则将两棵树合并成一颗树, 当算法终止的时候就只有一棵树了, 这颗树就是最小生成树;
1.3)Kruskal算法的执行步骤, 如下图所示,看个荔枝:

对上图的分析(Analysis):

  • A1)当添加到森林中的边足够多时算法终止, 实际上, 算法就是要决定边(u, v)应该添加还是放弃。(前一章节中的 Union/Find 算法在这里适用)

1.4)我们用到了一个恒定的事实:在算法实施的任意时刻,两个顶点属于同一个集合当且仅当它们在当前的森林中连通;因此, 每个顶点最初是在它自己的集合中;

  • 1.4.1) 如果u 和 v 在同一个集合中, 那么连接它们的边就要放弃, 因为由于它们已经连通 了,如果再添加一条边(u, v)就会形成一个圈了。
  • 1.4.2)如果这两个顶点不在同一个集合中, 则将该边加入, 并对包含顶点u 和 v 的这两个集合实施一次合并。
  • 1.4.3)容易看到,这样将保持集合不变性, 因为一旦边(u, v)添加到生成森林中, 若w连通到 u 而 x连通到v, 则x 和 w 必然是连通的, 因此属于相同集合 ;

1.5)固然,将边排序可便于选取,不过,用线性时间建立一个堆则是更好的想法;

  • 1.5.1)此时, deleteMin 将使得边依序得到测试。 典型情况下, 在算法终止前只有一小部分边需要测试, 尽管测试所有的边的情况是有可能的;例如,还有一个顶点 v8以及值为100的边(v5, v8),那么所有的边都会要考察到;

1.6)因为一条边由3个部分的数据组成, 所以在某些机器上吧优先队列实现成指向边的指针数组比实现成边的数组更为有效。

  • 1.6.1)这种实现的 效果在于, 为重新排列堆, 需要移动的只有那些指针, 而大量的记录则不必移动;

1.7)时间复杂度:该算法的最坏情形运行时间为 O(|E|log|E|), 它受堆操作控制。 注意, 由于 |E|=O(|V|^2), 因此这个运行时间实际上是 O(|E|log|V|)。在实践中, 该算法要比这个时间界指示的时间快得多;


【2】source code + printing results(将我的代码打印结果 同 “1.3” 上图中的手动模拟的 Kruskal 算法的结果进行比较,你会发现, 它们的结果完全相同,这也证实了我的代码的可行性)

2.0)code specification:

  • s1)本代码采用了优先队列(二叉小根堆)来升序选取边;
  • s2)本代码采用了用到了不相交集ADT的 find和setUion 操作来对边的两个vertexes 进行union 操作以及更新它们的根;
  • s3)对于根的初始化,我是这样初始化的—— parent[0]=-1,parent[1]=-2, parent[2]=-3, parent 说白了,就是 set的 一个 index, 所以开始肯定是不一样的; 然后,在union的时候,我只要检查是否 i == -parent[i]-1 就可以知道 它是否是树的根;
  • s4) 在合并的时候,要对边的两个顶点 start 和 end 的 parent做update, 这里涉及到4种情况—— start为根且end不为根;start为根且end为根;start为不为根且end为根;start不为根且end不为根; (干货,本代码的重中之重以及新颖之处)

2.1)download source code: https://github.com/pacosonTang/dataStructure-algorithmAnalysis/tree/master/chapter9/p240_kruskal
2.2)source code at a glance(for complete code , please click the given link above):

#include <stdio.h>
#include "binaryheap.h"// allocate memory for the vertexes with size
Vertex* makeEmptyVertexes(int size)
{Vertex *array; int i;array = (Vertex*)malloc(size * sizeof(Vertex)); if(!array){Error("out of space, from func makeEmptyVertexes");return NULL;} // initializing the set index towards every vertex with its array indexfor(i = 1; i <= size; i++)array[i-1] = -i;return array;
}void printParent(Vertex* vertexes, int size)
{int i;printf("\n\n\t the parent of every vertex at a glance");for(i=0; i<size; i++)printf("\n\t parent[%d] = %d", i, vertexes[i]);
}int find(Vertex *parent, Vertex single){while (single >= 0)single = parent[single]; return single;
}//judge whether the vertex index is the parent or not, also 1 or 0
//if the vertex under index is not the parent ,that's to say its parent is one of other vertexes
int isParent(Vertex *parent, Vertex index)
{return parent[index] == -index-1;
}void setUnion(Vertex *parent, Vertex start, Vertex end)
{   if(isParent(parent, start) ) // start is the parent {if(!isParent(parent, end)) // but end is not the parentend = find(parent, end) + 1; // find the parent of endparent[start] = end;        }else // start is not the parent {start = -find(parent, start) - 1; // find the parent of startif(!isParent(parent, end)) // but end is not the parentend = find(parent, end) + 1; // find the parent of endparent[end] = start;}
}void kruskal(BinaryHeap bh, int vertexNum)
{int counter;int set1;int set2; Vertex start;Vertex end;Vertex* parent;ElementType singleEdge; counter = 0;    parent = makeEmptyVertexes(vertexNum);while(counter < vertexNum - 1){singleEdge = deleteMin(bh);start = singleEdge.start;end = singleEdge.end;set1 = find(parent, start);set2 = find(parent, end);// find the set of vertex start and endif(set1 != set2){               setUnion(parent, start, end);counter++;printf("\n\t weight(v%d,v%d) = %d", singleEdge.start+1, singleEdge.end+1, singleEdge.weight);}       }printParent(parent, vertexNum);printf("\n\n\t");
}int main()
{  BinaryHeap bh;ElementTypePtr temp;    int vertexNum;int size = 7;int capacity;int i;int j;  int adjTable[7][7] = {{0, 2, 4, 1, 0, 0, 0},{2, 0, 0, 3, 10, 0, 0},{4, 0, 0, 2, 0, 5, 0},{1, 3, 2, 0, 7, 8, 4},{0, 10, 0, 7, 0, 0, 6},{0, 0, 5, 8, 0, 0, 1},{0, 0, 0, 4, 6, 1, 0},};  vertexNum = 7;capacity = vertexNum * vertexNum;bh = initBinaryHeap(capacity);temp = makeEmptyElement();printf("\n\n\t ====== test for kruskal alg building minimum spanning tree ======\n");//building binary heap with edge including 2 vertexs and its weight for(i = 0; i < size; i++){for(j = i+1; j < size; j++) if(adjTable[i][j]) {               temp->start = i;temp->end = j;temp->weight = adjTable[i][j];              insertHeap(temp, bh); // insertAdj the adjoining table over}}kruskal(bh, vertexNum);return 0;
} // allocate memory for the array with size
ElementTypePtr *makeEmptyArray(int size)
{ElementTypePtr *array;int i;array = (ElementTypePtr*)malloc(size * sizeof(ElementTypePtr)); if(!array){Error("out of space, from func makeEmptyArray");return NULL;}for(i=0; i<size; i++)    array[i] = makeEmptyElement();   return array;
}// allocate memory for the single element 
ElementTypePtr makeEmptyElement()
{ElementTypePtr temp;temp = (ElementTypePtr)malloc(sizeof(ElementType));if(!temp){Error("out of space, from func makeEmptyElement!");return NULL;}return temp;
}

2.3)printing results:
这里写图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/331869.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java 正则表达式 开头_如何在Java中修复表达式的非法开头

java 正则表达式 开头您是否遇到过这个令人难以置信的错误&#xff0c;想知道如何解决它&#xff1f; 让我们仔细阅读一下&#xff0c;研究如何解决表达式Java非法开头错误。 这是一个动态错误&#xff0c;这意味着编译器会发现某些不符合Java编程规则或语法的内容。 初学者大…

php mysql数据备份命令_MySQL数据备份与恢复的相关操作命令

将mysql安装目录设置到系统环境变量中, 方便在命令行终端直接执行.linux下mysql安装后, root默认密码为空, 可直接执行mysql 登录将mysql安装目录设置到系统环境变量中, 方便在命令行终端直接执行.linux下mysql安装后, root默认密码为空, 可直接执行mysql 登录.正常登录命令mys…

DFS——深度优先搜索基础

【0】README 0.1&#xff09; 本文总结于 数据结构与算法分析&#xff0c; 源代码均为原创&#xff0c; 旨在 review DFS——深度优先搜索 的基础知识&#xff1b; 【1】深度优先搜索的应用 1.1&#xff09;深度优先搜索算法描述&#xff08;转自天勤计算机考研高分笔记——数…

rest post put_REST / HTTP方法:POST与PUT与PATCH

rest post put每个HTTP请求都包含一个方法 &#xff08;有时称为verb &#xff09;&#xff0c;该方法指示对标识的资源执行的操作。 在构建RESTful Web服务时&#xff0c;HTTP方法POST通常用于创建资源&#xff0c;而PUT用于资源更新。 尽管在大多数情况下这很好&#xff0c;…

回归模型的score得分为负_深度研究:回归模型评价指标R2_score

回归模型的性能的评价指标主要有&#xff1a;RMSE(平方根误差)、MAE(平均绝对误差)、MSE(平均平方误差)、R2_score。但是当量纲不同时&#xff0c;RMSE、MAE、MSE难以衡量模型效果好坏。这就需要用到R2_score&#xff0c;实际使用时&#xff0c;会遇到许多问题&#xff0c;今天…

DFS应用——遍历无向图

【0】README 0.1&#xff09; 本文总结于 数据结构与算法分析&#xff0c; 源代码均为原创&#xff0c; 旨在 理解 如何对无向图进行深度优先搜索 的idea 并用源代码加以实现&#xff1b; 0.2&#xff09; 本文还引入了 背向边&#xff08;定义见下文描述&#xff09;&#x…

高效的磁力搜索引擎 -_高效的企业测试-结论(6/6)

高效的磁力搜索引擎 -该系列的最后一部分将涵盖其他端到端测试&#xff0c;生产中的测试以及各部分的结论。 进一步的端到端测试和生产中的测试 除了仅验证单个被测应用程序并模拟外部问题的系统测试之外&#xff0c;我们的管道还必须包括完整的端对端测试&#xff0c;以验证…

linux安装mysql phpmyadmin_ubuntu mysql远程连接+phpmyadmin安装

一、如何让ubuntu上的mysql允许远程连接进入MySQL&#xff0c;执行如下命令:use mysql;GRANT ALL PRIVILEGES ON *.* TO username% IDENTIFIED BY password WITH GRANT OPTION;flush privileges; //刷新select host,user from user; //查看是否成功退出mysql&#xff1b;打开su…

DFS应用——找出无向图的割点

【0】README 0.1&#xff09; 本文总结于 数据结构与算法分析&#xff0c; 源代码均为原创&#xff0c; 旨在 理解 “DFS应用于找割点” 的idea 并用源代码加以实现&#xff1b; 0.2&#xff09; 必须要事先 做个specification的是&#xff1a;对于给定图的除开起始vertex的那…

spock测试_将Spock 1.3测试迁移到Spock 2.0

spock测试了解Spock 2.0 M1&#xff08;基于JUnit 5&#xff09;的期望&#xff0c;如何在Gradle和Maven中迁移到它以及为什么报告发现的问题很重要&#xff1a;&#xff09;。 重要说明 。 我绝对不建议您永久将您的现实项目迁移到Spock 2.0 M1&#xff01; 这是2.x的第一个&…

mysql与jmeter环境变量配置_Java开发技术大杂烩(一)之Redis、Jmeter、MySQL的那些事...

前言毕业答辩告一段落&#xff0c;接下来好好努力工作。Redis遇到的一些问题DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to clients. In this mode connections …

DFS应用——寻找欧拉回路

【0】README 0.1&#xff09; 本文总结于 数据结构与算法分析&#xff0c; 源代码均为原创&#xff0c; 旨在 理解 “DFS应用——寻找欧拉回路” 的idea 并用源代码加以实现 &#xff08;源代码&#xff0c;我还没有找到一种有效的数据结构和DFS进行结合&#xff0c;往后会po出…

wiremock 使用_使用WireMock进行更好的集成测试

wiremock 使用无论您是遵循传统的测试金字塔还是采用诸如“ 测试蜂窝”这样的较新方法&#xff0c;都应该在开发过程中的某个时候开始编写集成测试。 您可以编写多种类型的集成测试。 从持久性测试开始&#xff0c;您可以检查组件之间的交互&#xff0c;也可以模拟调用外部服务…

mysql备份七牛云存储_定时备份 Mysql并上传到七牛的方法

多数应用场景下&#xff0c;我们需要对重要数据进行备份、并放置到一个安全的地方&#xff0c;以备不时之需。常见的 MySQL 数据备份方式有&#xff0c;直接打包复制对应的数据库或表文件(物理备份)、mysqldump 全量逻辑备份、xtrabackup 增量逻辑备份等。常见的数据存储方式有…

jetty java_Jetty,Java和OAuth入门

jetty java使用Okta的身份管理平台轻松部署您的应用程序 使用Okta的API在几分钟之内即可对任何应用程序中的用户进行身份验证&#xff0c;管理和保护。 今天尝试Okta。 Jetty是一个小型&#xff0c;高度可扩展的基于Java的Web服务器和servlet引擎。 它支持HTTP / 2&#xff0c…

DFS应用——查找强分支

【0】README 0.1&#xff09; 本文总结于 数据结构与算法分析&#xff0c; 源代码均为原创&#xff0c; 旨在 理解 “DFS应用——查找强分支” 的idea 并用源代码加以实现 &#xff1b; 【1】查找强分支 1.1&#xff09;如何检测一个图是否是强连通的&#xff1a; 通过执行两…

python中的super用法详解_Python中super函数用法实例分析

本文实例讲述了python中super函数用法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;这是个高大上的函数,在python装13手册里面介绍过多使用可显得自己是高手 23333. 但其实他还是很重要的. 简单说, super函数是调用下一个父类(超类)并返回该父类实例的方法. 这里的下…

java 管理多个进程_管理多个Java安装

java 管理多个进程随着越来越多的Java版本发布&#xff0c;在本地环境中管理多个Java安装将变得更加有趣。 不同的项目可能需要不同的Java版本。 jenv项目是管理Java安装的便捷方法。 它可以在全局&#xff0c;目录和外壳程序级别上设置本地Java安装&#xff0c;并使用易于记忆…

NP-完全性介绍

【0】README 0.1&#xff09; 本文总结于 数据结构与算法分析&#xff0c; 旨在 理解 “NP-完全性” 的idea &#xff1b; 【1】难与易 1.1&#xff09;不可判定问题&#xff1a;正如实数不足以表示 x^2 < 0 的解那样&#xff0c;可以证明&#xff0c; 计算机不可能解决碰…

python发邮件给多个人发送消息_python发送邮件(带附件)、发送给多人、抄送给多人的示例...

python发送邮件(带附件)、发送给多人、抄送给多人的示例#!/usr/bin/env python# -*-encoding: utf-8 -*-import smtplibfrom email.mime.multipart import MIMEMultipartfrom email.mime.text import MIMEText#image包可以发送图片形式的附件# from email.mime.image import MI…