图——图的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 (克鲁斯卡)实现:

 1    /* 最小、大生成树的 kruskal 算法 */
 2     SharedPointer< Array< Edge<E> > > kruskal(const bool MINMUM = true)
 3     {
 4         LinkQueue< Edge<E> > ret;  // 返回的队列
 5         SharedPointer< Array< Edge<E> > > edges = getUndirectedEdges();  // 将无相图中的所有边都拿到
 6         DynamicArray<int> p(vCount());  // 前驱标记数组
 7
 8         /* 设置前驱标记值 */
 9         for(int i=0; i<p.length(); i++)
10         {
11             p[i] = -1;
12         }
13
14         /* 对边数组排序 */
15         Sort::Shell(*edges, MINMUM);  // 第二个参数对边进行从大到小的次序排序,用来生成最大生成树
16
17         /* 进入循环,挑选边 */
18         for(int i=0; (i<edges->length()) && (ret.length() < (vCount()-1)); i++)  // 最多循环边的个数次,且如果边很多但已经有 N - 1 条边被选择了,那么结束循环
19 {
20             int b = find(p, (*edges)[i].b);  // 在前驱标记数组中查找挑选的边的两个顶点
21             int e = find(p, (*edges)[i].e);  // 前驱标记数组用于判断新选择的边是否会造成回路
22
23             if( b != e)  // 相等会构成回路
24             {
25                 p[e] = b;  // 修改前驱标记数组
26
27                 ret.add((*edges)[i]);  // 将这条边加入结果集合中去
28             }
29         }
30
31         if( ret.length() != (vCount()-1) )  // 判断边是否够,不够就不能构成最小生成树
32         {
33             THROW_EXCEPTION(InvalidOperationException, "No enough edges for Kruskal operation ...");
34         }
35
36         return toArray(ret);  // 将结果转换为数组
37     }

11,Kruskal 算法测试代码:

 1 #include <iostream>
 2 #include "MatrixGraph.h"
 3 #include "ListGraph.h"
 4
 5 using namespace std;
 6 using namespace DTLib;
 7
 8 template< typename V, typename E >
 9 Graph<V, E>& GraphEasy()
10 {
11    static MatrixGraph<4, V, E> g;
12
13     g.setEdge(0, 1, 1);
14     g.setEdge(1, 0, 1);
15     g.setEdge(0, 2, 3);
16     g.setEdge(2, 0, 3);
17     g.setEdge(1, 2, 1);
18     g.setEdge(2, 1, 1);
19     g.setEdge(1, 3, 4);
20     g.setEdge(3, 1, 4);
21     g.setEdge(2, 3, 1);
22    g.setEdge(3, 2, 1);
23
24     return g;
25 }
26
27 template< typename V, typename E >
28 Graph<V, E>& GraphComplex()
29 {
30    static ListGraph<V, E> g(9);
31
32     g.setEdge(0, 1, 10);
33     g.setEdge(1, 0, 10);
34     g.setEdge(0, 5, 11);
35     g.setEdge(5, 0, 11);
36     g.setEdge(1, 2, 18);
37     g.setEdge(2, 1, 18);
38     g.setEdge(1, 8, 12);
39     g.setEdge(8, 1, 12);
40     g.setEdge(1, 6, 16);
41     g.setEdge(6, 1, 16);
42     g.setEdge(2, 3, 22);
43     g.setEdge(3, 2, 22);
44     g.setEdge(2, 8, 8);
45     g.setEdge(8, 2, 8);
46     g.setEdge(3, 8, 21);
47     g.setEdge(8, 3, 21);
48     g.setEdge(3, 6, 24);
49     g.setEdge(6, 3, 24);
50     g.setEdge(3, 7, 16);
51     g.setEdge(7, 3, 16);
52     g.setEdge(3, 4, 20);
53     g.setEdge(4, 3, 20);
54     g.setEdge(4, 5, 26);
55     g.setEdge(5, 4, 26);
56     g.setEdge(4, 7, 7);
57     g.setEdge(7, 4, 7);
58     g.setEdge(5, 6, 17);
59     g.setEdge(6, 5, 17);
60     g.setEdge(6, 7, 19);
61    g.setEdge(7, 6, 19);
62
63     return g;
64 }
65
66 int main()
67 {
68     Graph<int, int>& g = GraphEasy<int, int>();
69    SharedPointer< Array< Edge<int> > > sa = g.kruskal(65535);
70
71    int w = 0;
72
73     for(int i=0; i<sa->length(); i++)
74     {
75         w += (*sa)[i].data;
76
77         cout << (*sa)[i].b << " " << (*sa)[i].e << " " << (*sa)[i].data << endl;
78    }
79
80    cout << "Weight: " << w << endl;
81
82     return 0;
83 }

13,小结:

1,Prim 算法以顶点为核心寻找最小生成树,不够直接;

2,Kruskal 算法以边为核心寻找最小生成树,直观简单;

3,Kruskal 算法中的关键是前驱标记数组的使用;

4,前驱标记数组用于判断新选择的边是否会造成回路;

原文地址:https://www.cnblogs.com/dishengAndziyu/p/10926585.html

时间: 2024-07-30 09:02:09

图——图的Kruskal法最小生成树实现的相关文章

图的基本算法(最小生成树)

假设以下情景,有一块木板.板上钉上了一些钉子.这些钉子能够由一些细绳连接起来.假设每一个钉子能够通过一根或者多根细绳连接起来.那么一定存在这种情况,即用最少的细绳把全部钉子连接起来. 更为实际的情景是这种情况.在某地分布着N个村庄.如今须要在N个村庄之间修路,每一个村庄之前的距离不同,问怎么修最短的路,将各个村庄连接起来. 以上这些问题都能够归纳为最小生成树问题,用正式的表述方法描写叙述为:给定一个无方向的带权图G=(V, E),最小生成树为集合T, T是以最小代价连接V中全部顶点所用边E的最小

看数据结构写代码(35) 图的邻接矩阵表示法

杂谈:最近清明小长假,好好的放松了一下.节前 和 节后 都有点 松懈.不好,不好.贵在坚持.加油. 图的邻接矩阵表示法是用 两个数组 来表示 图的数据结构.一个是顶点数组,另一个是邻接矩阵数组.邻接矩阵 里存放着 顶点的关系. 用邻接矩阵表示图,在 看 顶点之间 是否有边,或者 求顶点的度等操作时比较简单.但空间浪费巨大,在插入,删除 顶点 和边 操作时 需要 移动大量数据,造成不便.所以在插入删除比较多,节点数比较多的时候 不宜 使用这种结构. 下面上代码: 源代码网盘地址:点击打开链接 //

Prim和Kruskal求最小生成树

Prim: 算法步骤: 1.任意结点开始(不妨设为v1)构造最小生成树: 2.首先把这个结点(出发点)包括进生成树里, 3.然后在那些其一个端点已在生成树里.另一端点还未在生成树里的所有边中找出权最小的一条边, 4.并把这条边.包括不在生成树的另一端点包括进生成树, …. 5.依次类推,直至将所有结点都包括进生成树为止 Pascal的渣渣代码... 注:寻找最短的边那一步可以用堆优化,但那样还不如直接用Kruskal...... Reference: http://www.nocow.cn/in

POJ 1679 The Unique MST (Kruskal 判最小生成树是否唯一)

The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 21646 Accepted: 7661 Description Given a connected undirected graph, tell if its minimum spanning tree is unique. Definition 1 (Spanning Tree): Consider a connected, undirected

数据结构--图--图的数组存储表示,深度优先搜索遍历和广度优先搜索遍历

图有四种存储结构:数组,邻接表,十字链表,邻接多重表.下面以数组为存储结构来实现图的深度优先搜索遍历和广度优先搜索遍历.其中广度优先搜索遍历中有用到STL中的queue,注意头文件的包含.具体代码如下: //图的数组(邻接矩阵)存储表示和深度优先遍历 const int MAX_VERTEX_NUM=20; //最大顶点数 typedef enum {DG,DN,UDG,UDN} GraphKind ;//(有向图,有向网,无向图,无向网) typedef int VRType; typedef

给他任何一套图图图u又哭了

夫人和翻译秃头一天又图图图5634564646464合格合格合格和非官方的活动符合东方给他任何一套图图图u又哭了给他任何一套图图图u又哭了给他任何一套图图图u又哭了给他任何一套图图图u又哭了给他任何一套图图图u又哭了给他任何一套图图图u又哭了给他任何一套图图图u又哭了给他任何一套图图图u又哭了给他任何一套图图图u又哭了给他任何一套图图图u又哭了给他任何一套图图图u又哭了给他任何一套图图图u又哭了给他任何一套图图图u又哭了给他任何一套图图图u又哭了给他任何一套图图图u又哭了给他任何一套图图图u又哭

组队赛第五场 组合隔板法+最小生成树预处理并查集

UVALive 6434 题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4445 这题正好就是大一小学期的时候好像是曦曦出的那个牛那题吧,就是要买多少块板然后正好把牛给拦完.这题也是一样,就是找最大的距离,当做隔板,依次把最大的距离去掉,最后的就是最小的了. #include<iostream> #in

15 图-图的遍历-基于邻接矩阵实现的BFS与DFS算法

算法分析和具体步骤解说直接写在代码注释上了 TvT 没时间了等下还要去洗衣服 就先不赘述了 有不明白的欢迎留言交流!(估计是没人看的了) 直接上代码: 1 #include<stdio.h> 2 #include<queue> 3 #include<iostream> 4 using namespace std; 5 typedef struct{ 6 int Vex[10];//顶点表 7 int Edge[10][10]; 8 int vexnum,arcnum;

HDU6349-三原色图 Kruskal求最小生成树

三原色图 Time Limit: 1500/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 353    Accepted Submission(s): 134 Problem Description 度度熊有一张 n 个点 m 条边的无向图,所有点按照 1,2,?,n 标号,每条边有一个正整数权值以及一种色光三原色红.绿.蓝之一的颜色. 现在度度熊想选出恰好 k 条