最小生成树——Prim算法实现最小生成树
什么是最小生成树?
一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。最小生成树可以用kruskal(克鲁斯卡尔)算法或prim(普里姆)算法求出。
MST性质:
假设 N = (V, {E})是一个连通网,U是顶点集V的一个非空子集。若(u,v)是一条具有最小权值(代价)的边,其中 u ∈ U, v ∈ V - U,则必存在一棵包含边(u, v)的最小生成树。
证明如下(反证法):
假设连通网N的任何一棵最小生成树中都不包含边(u,v)。
设T是N的一棵最小生成树,则由上述假设可知,T中不包含(u,v)。由于T是连通的,因此有一条从u到v的路径。将T中的顶点集分为两部分:顶点集U和顶点集V - U,其中,顶点集U和相关的边构成一棵最小生成树T1,顶点集V - U和相关的边也构成一棵最小生成树T2,并且T1与T2之间只能有一条边,不妨设为(u`, v`),则u 和 u`之间、v和v`之间均是连通的。当把边(u,v)加入最小生成树T时,T中必有一条包含边(u,v)的回路,删除边(u`, v`),上述回路即被删除,由此得到另一棵生成树T`,如图所示。因为边(u,v)的权值小于等于(u`,v`)的权值,则T`的代价也就小于等于T的代价,因此T`也是N的最小生成树,且包含边(u,v),与假设矛盾,得证。
什么是Prim算法?
普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小。该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vojtěch Jarník)发现;并在1957年由美国计算机科学家罗伯特·普里姆(英语:Robert C. Prim)独立发现;1959年,艾兹格·迪科斯彻再次发现了该算法。因此,在某些场合,普里姆算法又被称为DJP算法、亚尔尼克算法或普里姆-亚尔尼克算法。
Prrim算法的基本思想是:假设N = (V, E)是连通网,令T = (U, TE)是N的最小生成树。算法的基本思想是:T的初始状态为U = {Vo} (Vo∈V),TE = {},重复执行下述操作:
① 在所有u∈U,v∈V - U的边(u,v)∈ E中,找一条代价最小的边(ui, vj)并入集合TE,同时将 vj 并入 U 中;
② 如此不断重复,知道 U = V 为止。此时 TE 必有 n - 1 条边,则 T(V,TE)为 N 的最小生成树。
连通图:
最小生成树:
Prim算法代码实现:
1 public class MST { 2 3 /** 4 * 这里用邻接矩阵来存储图 5 * 顶点编号从 A 开始,总共有7个顶点 6 * 这里需要声明一下,如果两个顶点没有边直接连接,那么就设置这连个顶点的权值(也可认为是距离,这里具体问题具体分析)无穷大 7 */ 8 private static int[][] closeMatrix = { 9 {0, 50, 60, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE}, 10 {50, 0, Integer.MAX_VALUE, Integer.MAX_VALUE, 40, Integer.MAX_VALUE, Integer.MAX_VALUE}, 11 {60, Integer.MAX_VALUE, 0, 52, Integer.MAX_VALUE, Integer.MAX_VALUE, 45}, 12 {Integer.MAX_VALUE, Integer.MAX_VALUE, 52, 0, 50, 30, 42}, 13 {Integer.MAX_VALUE, 40, Integer.MAX_VALUE, 50, 0, 70, Integer.MAX_VALUE}, 14 {Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, 30, 70, 0, Integer.MAX_VALUE}, 15 {Integer.MAX_VALUE, Integer.MAX_VALUE, 45, 42, Integer.MAX_VALUE, Integer.MAX_VALUE, 0}, 16 }; 17 18 private static char[] vex = {'A', 'B', 'C', 'D', 'E', 'F', 'G'}; 19 20 /** 21 * @param closeMatrix 22 * @param startVex 这里开始的顶点用数字表示,A-0 B-1 C-2 D-3 E-4 F-5 G-6 23 */ 24 public static void prim(int[][] closeMatrix, int startVex) { 25 // 两个辅助数组,因为随着点加入U中,可能原先是无穷大,后面直接变成最小都有可能,所以下面的两个数组的值都是在不停的变化 26 // lowCosts数组还有一个作用,如果lowCosts[i] == 0 表示编号为i的顶点已经加入到U集合中了,反之则没有加入U集合 27 // 这里是为想不改变原矩阵,所以才开了lowCosts作为辅助数组 28 int[] lowCosts = new int[vex.length]; 29 // closest数组是用来存储当前加入U集合中的顶点编号,作用:为了后面打印边时,能知道边左边的顶点编号 30 int[] closest = new int[vex.length]; 31 // 一开始加入第一个顶点时,初始化以上两个数组 32 // 加入一个顶点时没有边,所以不需要打印 33 for (int i = 0; i < vex.length; i++) { 34 lowCosts[i] = closeMatrix[startVex][i]; 35 closest[i] = startVex; 36 } 37 38 // k用于存储当前离U集合最近的顶点编号 39 int k = startVex; 40 // 开始加入V - U集合中的顶点,循环n - 1遍,该循环的目的:找出n - 1个顶点 41 for (int i = 1; i < vex.length; i++) { 42 // 找出离最小权值的边 43 int min = Integer.MAX_VALUE; 44 // 在V - U集合中找出离U最近的顶点k 45 for (int j = 0; j < vex.length; j++) { 46 if (lowCosts[j] != 0 && lowCosts[j] < min) { 47 // 更新 48 min = lowCosts[j]; 49 k = j; 50 } 51 } 52 // 程序运行到这,表示此时已经找到了我们想要找到的离U集合最近的顶点了,也可以将这里最近理解为代价最小或权值最小 53 // 打印边 54 System.out.printf("边(%c, %c)权为:%d\n", vex[closest[k]], vex[k], min); 55 // 不要忘了,标志编号为k的顶点已经加入U集合 56 lowCosts[k] = 0; 57 // 修改lowCosts 和 closest 数组 58 // 修改仍在V - U集合中的顶点,如果已经在U集合中的顶点不需要修改 59 for (int j = 0; j < vex.length; j++) { 60 // 现在要比的是编号为k的顶点,所有顶点以编号为k的顶点为参考点,如果此时到它的权值比之前的到上一个顶点时的更优,则更新 61 if (lowCosts[j] != 0 && closeMatrix[k][j] < lowCosts[j]) { 62 // 此时 lowCosts[j] 的值不再是一开始到开始第一加入的顶点时的权值了,而是到编号为k的顶点的权值 63 // 因为此时已经将k加入U集合,所有在 V - U集合中的顶点选取最小权值时都要以编号为k的顶点作为基点展开 64 lowCosts[j] = closeMatrix[k][j]; 65 // 更新k,这一行至关重要 66 closest[j] = k; 67 } 68 } 69 } 70 } 71 72 public static void main(String[] args) { 73 prim(closeMatrix, 0); 74 } 75 }
运行结果:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· DeepSeek在M芯片Mac上本地化部署
· 葡萄城 AI 搜索升级:DeepSeek 加持,客户体验更智能