本文主要是介绍无向连通网的最小生成树算法[第1部分],希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
摘要:求解图的最小生成树在工程管理、最优化规划等领域有广泛的应用,因此对最小生成树算法的研究具有重要的意义。本文针对图的最小生成树算法,首先对几种经典的最小生成树算法进行了总结,最后针对无向连通网的最小生成树问题,分别使用普利姆算法和克鲁斯卡尔算法进行了详细的算法原理分析与程序实现。
关键词:无向连通网;最小生成树算法;普利姆算法;克鲁斯卡尔算法
The Minimum Spanning Tree Algorithm of undirected connected network
Abstract:The minimum spanning tree of graphs is widely used in engineering management, optimization planning and other areas, so it is very important to study the minimum spanning tree algorithm. In this paper, Several classical minimum spanning tree algorithms are summarized, At the same time, a detailed algorithm analysis and program realization are carried out for the minimum spanning tree problem of undirected connected network by using the Prim algorithm and the Kruskal algorithm.
Key words:Undirected connected network;MST;Prim algorithm;Kruskal algorithm
1 引 言
求解图的最小生成树(Minimum Spanning Tree,MST)属于图论的典型应用问题。其中,连通图的最小生成树在理论研究和工程设计上均有广泛的研究和应用,因此最小生成问题从提出到理论描述,再到算法实现方式都取得了丰富的研究和应用成果。迄今为止,国内外学者就最小生成树问题,分别针对有向图和无向图提出了多种解决策略。其中,针对带权值的有向图,吴文虎等[1]提出了通过有向圈的收缩和展开求解最小生成树的策略;冯俊文[2]等提出了基于表格表示的表上作业法;对于无向图的最小生成树算法,包含Prim算法、Kruskal算法、Dijkstra最小生成树等经典的求解算法[3]。本文针对无向连通网的最小生成树问题,首先针对经典的Prim算法通过从部分最小生成树边集合扩展的角度逐步从剩余候选边集中选取最小边构造最小生成树;针对Kruskal算法可能的环路问题,通过使用并查集[4-5]来对所选的边进行连通分量的判断,同时对所选边集合进行路径压缩提高下一次查询效率。最后给出了详细的算法设计流程和实例验证。
2 算法描述
最小生成树问题在实际的工程管理、最优化规划等方面有实际的应用价值,例如交通路网的规划、旅行路线规划、通信网络设计、故障诊断[6-7]等。因此在基于图论的应用问题中,通常需要对带权值的无向连通图求最小生成。在求无向连通网的最小生成树时,需要预先构造一个带权值的无向连通图并用邻接矩阵表示图的存储结构,无向连通网和邻接矩阵表示分别如下所示(其中*表示距离为无穷)。
在最小生成树的求解算法中,Prim算法和kruskal算法使用最为广泛,本文利用Prim算法和Kruskal算法思想进行详细的程序设计与求解验证。
2.1 Prim算法
2.2 Kruskal算法
3 算法实现描述
3.1 Prim算法实现描述
根据Prim算法的思想和伪代码,在程序开始时需要给定一个连通网并给出一个初始顶点。接着从最小生成树边集合扩展的角度,从剩余结点和边中选择出权值最小的边,分别加入生成树的顶点集合和边集合。由于对于连通网其生成树总是存在的,因此根据生成树的性质,对于N个结点的连通网,需要N-1条边是的任意两个结点之间相互连通,那么算法结束的条件满足经过N-1此迭代,并在每一次迭代中选择出权值最小的边。如果在任意一次迭代过程中,不存在由已经加入生成树和剩余顶点集之间取值最小的边,则该连通网的输入数据存在错误导致图不连通。
为了方便实现边信息的表示,定义一个结构体类型的边结点edgeNode,该结点中存储边的起始顶点from、终点顶点to以及边的权值cost,同时定义邻接矩阵AdjMatrix和边集合数组edgeSet。
为了表述普利姆算法边和顶点的加入过程,使用流程图[8]来表示整个程序各实现步骤之间的逻辑关系,普利姆算法程序运行流程图如下:
3.2 Kruakal算法实现描述
根据Kruskal算法的思想和伪代码,程序在开始的时候需要对连通网中的边按照权值排序,接着从边集合扩展的角度,从剩余边集中选择最小的边,若所选边加入后不构成环路,则分别将边和顶点加入生成树的顶点集合和边集合。由于无向连通网的生成树总是存在的,根据生成树性质,对于N个结点的连通图,需要N-1条边使得任意两个结点之间相互连通,因此算法结束的条件是从边集中选择N-1条边。如果所有的边遍历完,选择边的数量小于N-1,则该连通网的输入数据存在错误导致图不连通。
4 算法实现及主要函数模块说明
为了实现Prim算法和Kruskal算法,程序中定义了边结点用来表示一条边的两个顶点及权值数据,边结点edgeNode定义如下:
typedef struct edgeNode
{
int from,to;
int cost;
}
EDGENODE;
4.1 Prim算法及主要的功能函数模块说明
(1)creatMatrix函数模块
函数原型:void creatMatrix(int **AdjMatrix,int n,int e);
函数功能:以文件读入或者键盘输入的方式构造邻接矩阵,AdjMatrix表示邻接矩阵,n和e分别表示图的顶点数和边数。
(2)printMatrix函数模块
函数原型:void printMatrix(int **AdjMatrix,int n);
函数功能:输出邻接矩阵,AdjMatrix表示邻接矩阵,n表示图的顶点数。
(3)initEdgeSet函数模块
函数原型:void initEdgeSet(int **AdjMatrix,EDGENODE *edgeSet,int n,int start);
函数功能:将start与其他顶点之间的权值存放到候选边集合edgeSet中。
(4)chooseEdge函数模块
函数原型:int chooseEdge(EDGENODE *edgeSet,int n,int index);
函数功能:从候选边集edgeSet中选出最小边结点,其中 index为edgeSet选取边时下标的起始位置。
(5)modfiyEdgeSet函数模块
函数原型:void modfiyEdgeSet(int **AdjMatrix,EDGENODE *edgeSet,int n,int index,int to);
函数功能:新加入结点后,调整候选边集edgeSet中的待选边结点,其中to为新加入到中的顶点编号。
(6)primMst最小生成树函数模块
函数原型:void primMst(int **AdjMatrix,EDGENODE *edgeSet,int n,int start);
函数功能:通过顶点从候选边集中选取最小边构造最小生成树。
(7)printMst最小生成树输出函数模块
函数原型:void printMst(EDGENODE *edgeSet,int n);
函数功能:输出最终最小生成树中的选取的边和最小权值和。
这篇关于无向连通网的最小生成树算法[第1部分]的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!