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法最小生成树实现的更多相关文章

  1. 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)= ...

  2. c/c++ 图的创建及图的相关函数(链表法)

    c/c++ 图的创建及图的相关函数(链表法) 图的概念 图由点和线组成 知道了图中有多少个点,和哪些点之间有线,就可以把一张图描绘出来 点之间的线,分有方向和无方向 创建图 创建图,实际就是创建出节点 ...

  3. 图——图的Prim法最小生成树实现

    1,运营商的挑战: 1,在下图标出的城市间架设一条通信线路: 2,要求: 1,任意两个城市间都能够通信: 2,将架设成本降至最低: 2,问题抽象: 1,如何在图中选择 n - 1 条边使得 n 个顶点 ...

  4. 【算法导论】最小生成树之Kruskal法

    在图论中,树是指无回路存在的连通图.一个连通图的生成树是指包含了所有顶点的树.如果把生成树的边的权值总和作为生成树的权,那么权值最小的生成树就称为最小生成树.因为最小生成树在实际中有很多应用,所以我们 ...

  5. 图的Prim,Kruskal,Dijkstra,Floyd算法

    代码部分有点问题,具体算法没问题, 最近期末考,要过段时间才会修改 //邻接矩阵,具体情况看上一篇的图的实现template<class T>class MGraph {public:   ...

  6. 图——图的Floyd法最短路径实现

    1,Dijkstra 算法一次性求得起始顶点到所有其它顶点的最短路径,如果想要求解任意两个顶点之间的最短路径,可将图中顶点作为起始顶点执行 n 次 Dijkstra 算法就可以了: 2,可能解决方案: ...

  7. 图——图的Dijkstra法最短路径实现

    1,最短路径的概念: 1,从有向图中某一顶点(起始顶点)到达另一顶点(终止顶点)的路径中,其权值之和最小的路径: 2,问题的提法: 1,给定一个带权有向图 G 与起始顶点 v,求从 v 到 G 中其它 ...

  8. #图# #最大生成树# #kruskal# ----- OpenJudge 799:Heavy Transportation

    OpenJudge 799:Heavy Transportation 总时间限制: 3000ms 内存限制: 65536kB 描述BackgroundHugo Heavy is happy. Afte ...

  9. java用Kruskal实现最小生成树

    今天更新这篇文章超级激动,因为我会最小生成树的算法了(其实昨天就开始研究了,只是昨天参加牛客网的算法比赛,结果又被虐了,好难过~) 最小生成树的算法,其实学了数据结构就会有一定的基础,Kruskal算 ...

随机推荐

  1. js对象的创建模式

    方式一: Object构造函数模式 * 套路: 先创建空Object对象, 再动态添加属性/方法 * 适用场景: 起始时不确定对象内部数据 * 问题: 语句太多 /* 一个人: name:" ...

  2. tomcat7 与tomcat8 使用tomcat dbcp pool注意对应类变化

    tomcat dbcp pool在tomcat 7 和tomcat8下的jar包有变化,相应包名也发生变化,对应类名有相应变化! tomcat的lib文件夹下会有jar包tomcat-dbcp.jar ...

  3. Linux入门培训教程 linux下拷贝cp删除rm移动mv命令参数以及说明

    拷贝移动删除在windows中看起来这么简单,但linux经常使用的文字界面,所以对于linux系统 下拷贝cp删除 rm 移动mv命令参数就不得不需要了解和学习了 cp 该命令的功能是将给出的文件或 ...

  4. IDEA中Springboot静态文件加载(热部署)

    Springboot项目静态文件加载 昨天写项目的时候碰到一个问题,就是静态文件css无法读取到项目中,我仔细思考了下,总结了下,可能有两个问题 1.页面未加载更新 这个可能性非常大,Chrome就是 ...

  5. Tomcat的安装、配置常见问题

    (1)服务里面没有Tomcat怎么办? ——运行:cmd=>再到Tomcat 8.0/bin目录下运行: service install  即可: ——然后用: net start   Tomc ...

  6. Spring Boot教程(二十四)Web应用的统一异常处理

    我们在做Web应用的时候,请求处理过程中发生错误是非常常见的情况.Spring Boot提供了一个默认的映射:/error,当处理中抛出异常之后,会转到该请求中处理,并且该请求有一个全局的错误页面用来 ...

  7. Spring Cloud架构教程 (三)服务网关(基础)

    通过之前几篇Spring Cloud中几个核心组件的介绍,我们已经可以构建一个简略的(不够完善)微服务架构了.比如下图所示: alt 我们使用Spring Cloud Netflix中的Eureka实 ...

  8. spring security跳过认证

    在启动springboot的时候,给启动注解后添加这个exclude参数后接想要跳过的类就不会加载它了. @SpringBootApplication(exclude = { org.springfr ...

  9. @清晰掉 GNU C __attribute__

    __attribute__((packed))详解 1. __attribute__ ((packed)) 的作用就是告诉编译器取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐,是GCC特有 ...

  10. leetcode-mid-sorting and searching - 33. Search in Rotated Sorted Array

    mycode class Solution(object): def search(self, nums, target): """ :type nums: List[i ...