图——图的Kruskal法最小生成树实现
1,最小生成树的特征:
1,选取的边是图中权值较小的边;
2,所有边连接后不构成回路;
2,prim 算法是以顶点为核心的,最下生成树最大的特征是边,但 prim 算法非要以顶点为核心来进行,有些复杂和难以理解;
3,既然最小生成树关心的是如何选择 n - 1 条边,那么是否可以直接以边为核心进行算法设计?
4,简单尝试:
1,由 4 个顶点构成的图,选择 3 条权值最小的边;
2,还要设法避免回路;
5,需要解决的问题:
1,如何判断新选择的边与已选择的边是否构成回路?
6,技巧:前驱标记数组(避开新加入边造成回路问题)
1,定义数组:Array<int> p(vCount());
2,定义数组元素的意义:
1,p[n] 表示顶点 n 在边的连接通路上的另一端顶点;
3,前驱标记数组究竟是怎么来的?
7,最小生成树算法的核心步骤(Kruskal):
1,定义前驱标记数组:Array<int> p(vCount());
2,获取当前图中的所有边,并存储于 edges 数组中;
3,对数组 deges 按照权值进行排序;
4,利用 p 数组在 edges 数组中选择前 n - 1 不构成回路的边;
8,Kruskal 算法流程:
9,关键的 find 查找函数:
10,最小生成树算法 Kruskal (克鲁斯卡)实现:
/* 最小、大生成树的 kruskal 算法 */
SharedPointer< Array< Edge<E> > > kruskal(const bool MINMUM = true)
{
LinkQueue< Edge<E> > ret; // 返回的队列
SharedPointer< Array< Edge<E> > > edges = getUndirectedEdges(); // 将无相图中的所有边都拿到
DynamicArray<int> p(vCount()); // 前驱标记数组 /* 设置前驱标记值 */
for(int i=; i<p.length(); i++)
{
p[i] = -;
} /* 对边数组排序 */
Sort::Shell(*edges, MINMUM); // 第二个参数对边进行从大到小的次序排序,用来生成最大生成树 /* 进入循环,挑选边 */
for(int i=; (i<edges->length()) && (ret.length() < (vCount()-)); i++) // 最多循环边的个数次,且如果边很多但已经有 N - 1 条边被选择了,那么结束循环
{
int b = find(p, (*edges)[i].b); // 在前驱标记数组中查找挑选的边的两个顶点
int e = find(p, (*edges)[i].e); // 前驱标记数组用于判断新选择的边是否会造成回路 if( b != e) // 相等会构成回路
{
p[e] = b; // 修改前驱标记数组 ret.add((*edges)[i]); // 将这条边加入结果集合中去
}
} if( ret.length() != (vCount()-) ) // 判断边是否够,不够就不能构成最小生成树
{
THROW_EXCEPTION(InvalidOperationException, "No enough edges for Kruskal operation ...");
} return toArray(ret); // 将结果转换为数组
}
11,Kruskal 算法测试代码:
#include <iostream>
#include "MatrixGraph.h"
#include "ListGraph.h" using namespace std;
using namespace DTLib; template< typename V, typename E >
Graph<V, E>& GraphEasy()
{
static MatrixGraph<, V, E> g; g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , ); return g;
} template< typename V, typename E >
Graph<V, E>& GraphComplex()
{
static ListGraph<V, E> g(); g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , );
g.setEdge(, , ); return g;
} int main()
{
Graph<int, int>& g = GraphEasy<int, int>();
SharedPointer< Array< Edge<int> > > sa = g.kruskal(); int w = ; for(int i=; i<sa->length(); i++)
{
w += (*sa)[i].data; cout << (*sa)[i].b << " " << (*sa)[i].e << " " << (*sa)[i].data << endl;
} cout << "Weight: " << w << endl; return ;
}
13,小结:
1,Prim 算法以顶点为核心寻找最小生成树,不够直接;
2,Kruskal 算法以边为核心寻找最小生成树,直观简单;
3,Kruskal 算法中的关键是前驱标记数组的使用;
4,前驱标记数组用于判断新选择的边是否会造成回路;
图——图的Kruskal法最小生成树实现的更多相关文章
- matlab学习——04图与网络(最短路,最小生成树,最大流)
04图与网络 1.最短路 (1) 自己写的dijstra算法 format compact; clc,clear all a=zeros(6); a(1,2)=50;a(1,4)=40;a(1,5)= ...
- c/c++ 图的创建及图的相关函数(链表法)
c/c++ 图的创建及图的相关函数(链表法) 图的概念 图由点和线组成 知道了图中有多少个点,和哪些点之间有线,就可以把一张图描绘出来 点之间的线,分有方向和无方向 创建图 创建图,实际就是创建出节点 ...
- 图——图的Prim法最小生成树实现
1,运营商的挑战: 1,在下图标出的城市间架设一条通信线路: 2,要求: 1,任意两个城市间都能够通信: 2,将架设成本降至最低: 2,问题抽象: 1,如何在图中选择 n - 1 条边使得 n 个顶点 ...
- 【算法导论】最小生成树之Kruskal法
在图论中,树是指无回路存在的连通图.一个连通图的生成树是指包含了所有顶点的树.如果把生成树的边的权值总和作为生成树的权,那么权值最小的生成树就称为最小生成树.因为最小生成树在实际中有很多应用,所以我们 ...
- 图的Prim,Kruskal,Dijkstra,Floyd算法
代码部分有点问题,具体算法没问题, 最近期末考,要过段时间才会修改 //邻接矩阵,具体情况看上一篇的图的实现template<class T>class MGraph {public: ...
- 图——图的Floyd法最短路径实现
1,Dijkstra 算法一次性求得起始顶点到所有其它顶点的最短路径,如果想要求解任意两个顶点之间的最短路径,可将图中顶点作为起始顶点执行 n 次 Dijkstra 算法就可以了: 2,可能解决方案: ...
- 图——图的Dijkstra法最短路径实现
1,最短路径的概念: 1,从有向图中某一顶点(起始顶点)到达另一顶点(终止顶点)的路径中,其权值之和最小的路径: 2,问题的提法: 1,给定一个带权有向图 G 与起始顶点 v,求从 v 到 G 中其它 ...
- #图# #最大生成树# #kruskal# ----- OpenJudge 799:Heavy Transportation
OpenJudge 799:Heavy Transportation 总时间限制: 3000ms 内存限制: 65536kB 描述BackgroundHugo Heavy is happy. Afte ...
- java用Kruskal实现最小生成树
今天更新这篇文章超级激动,因为我会最小生成树的算法了(其实昨天就开始研究了,只是昨天参加牛客网的算法比赛,结果又被虐了,好难过~) 最小生成树的算法,其实学了数据结构就会有一定的基础,Kruskal算 ...
随机推荐
- yaf 生成项目
yaf 生成项目 yaf下载安装地址 https://github.com/laruence/yaf/releases 生成项目 一定需要在安装yaf的php版本环境中执行该语句 sudo /usr/ ...
- ef复杂模型添加
模型浏览器 函数导入-添加存储过程名称 添加复杂实体.复杂实体可以手动在xml里面创建.在complextype里面
- js for循环 框架内部的
var head001 =true; var head002 = true; var head003 = true; ; h++) { console.log(h); } h=; ;h < ; ...
- jquery eq()选择器 语法
jquery eq()选择器 语法 作用::eq() 选择器选取带有指定 index 值的元素.index 值从 0 开始,所有第一个元素的 index 值是 0(不是 1).经常与其他元素/选择器一 ...
- luogu P1352 没有上司的舞会 x
P1352 没有上司的舞会 题目描述 某大学有N个职员,编号为1~N.他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司.现在有个周年庆宴会,宴会每邀请来一个职员 ...
- 装RAC跑脚本报错
在执行第二个脚本的时候报错 原因是在改服务器找不到该包 解决方法: 挂载iso镜像,安装这个包
- CDH搭建和集成spark、kafka操作
系统:Centos7 CDH版本:5.14.0 请自己提前安装好:mysql.jdk 并下载好相关依赖(每一台机器) yum -y install chkconfig python bind-util ...
- Java连接Oracle数据库常用方法
JDBC的六大步骤: 注册驱动 获取连接 获取执行sql语句对象 执行sql语句 处理结果集 关闭资源 oracle URL: jdbc:oracle:thin:@localhost:1521:SID ...
- JDBC API访问数据库的基本步骤。
JDBC本质:官方定义了一套操作所有关系型数据库的规则(接口),各个数据库厂商实现这个接口,提供数据库驱动jar包. 我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类. 任 ...
- windows server 2008 r2 配置ftp (FileZilla Server )
1.需要个ftp 2.在华为云内部,用IIS,配置后如果用主动模式,客户端需要配置后客户端需要做配置才能访问,去掉√,见下图. 3.华为云的教程,配被动需要把1024以上的端口都放开,不安全! 但客户 ...