java实现最小生成树的prim算法和kruskal算法
在边赋权图中,权值总和最小的生成树称为最小生成树。构造最小生成树有两种算法,分别是prim算法和kruskal算法。在边赋权图中,如下图所示:

在上述赋权图中,可以看到图的顶点编号和顶点之间邻接边的权值,若要以上图来构建最小生成树。结果应该如下所示:

这样构建的最小生成树的权值总和最小,为17
在构建最小生成树中,一般有两种算法,prim算法和kruskal算法
在prim算法中,通过加入最小邻接边的方法来建立最小生成树算法。首先构造一个零图,在选一个初始顶点加入到新集合中,然后分别在原先的顶点集合中抽取一个顶点,使得构成的边为权值最小,然后将该笔边加入到图中,并将抽出的顶点加入到新集合中,重复这个过程,知道新集合等于原先的集合。
代码一:(java)
/**
* 最小生成树的prim算法
* @author liuy
*/
public class Prim { public static void prim(int num, float[][] weight) { //num为顶点数,weight为权
float[] lowcost = new float[num + 1]; //到新集合的最小权 int[] closest = new int[num + 1]; //代表与s集合相连的最小权边的点 boolean[] s = new boolean[num + 1]; //s[i] == true代表i点在s集合中 s[1] = true; //将第一个点放入s集合 for(int i = 2; i <= num; i++) { //初始化辅助数组
lowcost[i] = weight[1][i];
closest[i] = 1;
s[i] = false;
} for(int i = 1; i < num; i++) {
float min = Float.MAX_VALUE;
int j = 1;
for(int k = 2; k <= num; k++) {
if((lowcost[k] < min) && (!s[k])) {//根据最小权加入新点
min = lowcost[k];
j = k;
}
} System.out.println("加入点" + j + ". " + j + "---" + closest[j]);//新加入点的j和与j相连的点 s[j] = true;//加入新点j for(int k = 2; k <= num; k++) {
if((weight[j][k] < lowcost[k]) && !s[k]) {//根据新加入的点j,求得最小权
lowcost[k] = weight[j][k];
closest[k] = j;
}
}
}
} public static void main(String[] args) {
// ①
// / | /
// 6 1 5
// / | /
// ②-5--③--5--④
// / // /
// 3 6 4 2
// // //
// ⑤--6-⑥
//最小生成树为:
// ①
// |
// 1
// |
// ②-5--③ ④
// / / /
// 3 4 2
// / //
// ⑤ ⑥
//
float m = Float.MAX_VALUE;
float[][] weight = {{0, 0, 0, 0, 0, 0, 0},
{0, m, 6, 1, 5, m, m},
{0, 6, m, 5, m, 3, m},
{0, 1, 5, m, 5, 6, 4},
{0, 5, m, 5, m, m, 2},
{0, m, 3, 6, m, m, 6},
{0, m, m, 4, 2, 6, m}};//上图的矩阵
prim(weight.length - 1, weight);
//加入点3. 3---1
//加入点6. 6---3
//加入点4. 4---6
//加入点2. 2---3
//加入点5. 5---2
}
}
代码二:(java)
package 最小生成树;
/*
* 最小生成树prim算法,加入最小邻接边生成最小生成树。
* 首先构造一个零图,选择一个初始点加入到集合中,
* 然后分别从原来顶点的集合中抽取一个顶点,
* 选择的标准是构造成的树的权值最小,
* 循序渐进最终生成一棵最小生成树
*/
public class prim { /*
* m:定义为无法到达的距离
* weight:邻接矩阵表,weight表示权值
* verNum:顶点的个数
* lowerW:到新集合的最小权值
* edge:存储到新集合的边
* checked:判定顶点是否被抽取的集合
*/ static int m=Integer.MAX_VALUE;
static int[][] weight={
{0, 0, 0, 0, 0, 0},
{0, m, 6, 9, 5, 13},
{0, 6, m, 6,7,8},
{0, 9,6,m,9,3},
{0, 5,7,9,m,3},
{0,13,8,3,3,m}
};
static int verNum=weight.length;
static int []lowerW=new int[verNum];
static int []edge=new int[verNum];
static boolean []checked=new boolean[verNum]; public void prim(int n,int [][]w){
checked[1]=true; //抽取第一个顶点 for(int i=1;i<=n;i++){ //初始化顶点集合
lowerW[i]=w[1][i];
edge[i]=1;
checked[i]=false;
} for(int i=1;i<=n;i++){
int min=Integer.MAX_VALUE;
int j=1;
for(int k=2;k<=n;k++){ //判定是否抽取该顶点
if(lowerW[k]<min&&(!checked[k])){
min=lowerW[k];
j=k;
}
}
if(i<n) //避免输出第一个顶点到第一个顶点的情况
System.out.println(j+"-->"+edge[j]); checked[j]=true; //将顶点加入到新集合中 for(int k=2;k<=n;k++){ //根据新加入的顶点,求得最小的权值
if((w[j][k]<lowerW[k])&&(!checked[k])){
lowerW[k]=weight[j][k];
edge[k]=j;
}
}
}
} public static void main(String[] args) {
// TODO Auto-generated method stub
prim p=new prim();
p.prim(verNum-1,weight);
}
}
在kruskal算法中,根据边的权值以递增的方式逐渐建立最小生成树。具体操作是:将赋权图每个顶点都看做森林,然后将图中每条邻接边的权值按照升序的方式进行排列,接着从排列好的邻接边表中抽取权值最小的边,写入该边的起始顶点和结束顶点,连接顶点将森林构成树,然后读取起始结束顶点的邻接边,优先抽取权值小的邻接边,继续连接顶点将森林构成树。添加邻接边的要求是加入到图中的邻接边不构成回路。如此反复进行,直到已经添加n-1条边为止。
代码一:(java)
package 最小生成树;
import java.util.ArrayList;
import java.util.Scanner;
/*
* 最小生成树kruskal算法:首先将每个顶点作为一棵森林,升序比较该顶点的邻接边,
* 每次取最小权值的邻接边,将该邻接边连接的顶点与原先顶点构成一棵树,接着寻找
* 下一个顶点,继续按照邻接边权值升序进行比较,取权值最小的构成树...
*
* 该类用一个Edge类构成一个邻接边的信息,包括邻接边的起始顶点与结束顶点,权值。
* 用类Edge创建对象,录入对象信息,按照对象的权值进行比较,符合条件的对象加入
* 到链表中,最终按照链表顺序输出最小生成树。
*/
public class kruskal { /*
* Max:定义顶点数组的最大值
* edge:链表edge,存储构造的Edge对象
* target:链表trget,存储最终得到结果的Edge对象
* parent:存储顶点信息的数组
* n:顶点数
*/
int Max=100;
ArrayList<Edge>edge=new ArrayList<Edge>();
ArrayList<Edge>target=new ArrayList<Edge>();
int[] parent=new int[Max];
Float TheMax=Float.MAX_VALUE;
int n; public void init(){
/**
* p:起始顶点
* q:结束顶点
* w:边的权值
* n:顶点个数
*/
Scanner scan =new Scanner(System.in);
int p,q;
double w;
System.out.println("请输入结点的个数:");
n=scan.nextInt();
System.out.println("按照'A,B,C'的格式输入边与边的信息,ABC分别代表边的起始顶点,结束顶点,权值(输入-1 -1 -1结束输入):");
while(true){
p=scan.nextInt();
q=scan.nextInt();
w=scan.nextDouble();
if(p<0||q<0||w<0)break;
Edge e=new Edge();
e.start=p;
e.end=q;
e.weight=w;
edge.add(e);
}
for(int i=1;i<=n;++i){ //初始化边的信息数组
parent[i]=i;
}
} /*
* 对象合并,将上一对象的结束边作为下一对象的起始边
*/
public void union(int j,int k){
for(int i=1;i<=n;++i){
if(parent[i]==j)
parent[i]=k;
}
} public void kruskal(){
int i=0; //顶点
while(i<n-1&&edge.size()>0){ //如果只有一条边或者没有边跳出
double min=Double.MAX_VALUE;
Edge temp=null;
for(int j=0;j<edge.size();++j){ //遍历图形
Edge tt=edge.get(j);
if(tt.weight<min){ //若两个顶点有权值,即相连
min=tt.weight;
temp=tt;
}
} //构造一棵树
int jj=parent[temp.start];
int kk=parent[temp.end]; if(jj!=kk){
++i; //以end作为下一条边的start,寻找下一条边
target.add(temp); //将找到的边放入目标集合中
union(jj,kk);
}
edge.remove(temp); //将临时边删除
}
System.out.println("最小生成树的路径是:");
for(int k=0;k<target.size();++k){ //输出最小生成树
Edge e=target.get(k);
System.out.println(e.start+"-->"+e.end);
}
} public static void main(String[] args) {
// TODO Auto-generated method stub
kruskal kr=new kruskal();
kr.init();
kr.kruskal();
}
}
/*
* start:起始顶点
* end:结束顶点
* weight:权值
*/
class Edge{
public int start;
public int end;
public double weight;
}
java实现最小生成树的prim算法和kruskal算法的更多相关文章
- 最小生成树之Prim算法和Kruskal算法
最小生成树算法 一个连通图可能有多棵生成树,而最小生成树是一副连通加权无向图中一颗权值最小的生成树,它可以根据Prim算法和Kruskal算法得出,这两个算法分别从点和边的角度来解决. Prim算法 ...
- 【数据结构】最小生成树之prim算法和kruskal算法
在日常生活中解决问题经常需要考虑最优的问题,而最小生成树就是其中的一种.看了很多博客,先总结如下,只需要您20分钟的时间,就能完全理解. 比如:有四个村庄要修四条路,让村子能两两联系起来,这时就有最优 ...
- 最小生成树之 prim算法和kruskal算法(以 hdu 1863为例)
最小生成树的性质 MST性质:设G = (V,E)是连通带权图,U是V的真子集.如果(u,v)∈E,且u∈U,v∈V-U,且在所有这样的边中, (u,v)的权c[u][v]最小,那么一定存在G的一棵最 ...
- 最小生成树(prim算法和kruskal算法)
学习博客:https://www.cnblogs.com/zhangming-blog/p/5414514.html 其实就是加点法:从不属于这个集合的点中找从本集合可以找到的最小边,加入本集合 看代 ...
- 转载:最小生成树-Prim算法和Kruskal算法
本文摘自:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html 最小生成树-Prim算法和Kruskal算法 Prim算 ...
- 最小生成树——Prim算法和Kruskal算法
洛谷P3366 最小生成树板子题 这篇博客介绍两个算法:Prim算法和Kruskal算法,两个算法各有优劣 一般来说当图比较稀疏的时候,Kruskal算法比较快 而当图很密集,Prim算法就大显身手了 ...
- 最小生成树Prim算法和Kruskal算法
Prim算法(使用visited数组实现) Prim算法求最小生成树的时候和边数无关,和顶点树有关,所以适合求解稠密网的最小生成树. Prim算法的步骤包括: 1. 将一个图分为两部分,一部分归为点集 ...
- Prim算法和Kruskal算法
Prim算法和Kruskal算法都能从连通图找出最小生成树.区别在于Prim算法是以某个顶点出发挨个找,而Kruskal是先排序边,每次选出最短距离的边再找. 一.Prim(普里姆算法)算法: ...
- Prim算法和Kruskal算法的正确性证明
今天学习了Prim算法和Kruskal算法,因为书中只给出了算法的实现,而没有给出关于算法正确性的证明,所以尝试着给出了自己的证明.刚才看了一下<算法>一书中的相关章节,使用了切分定理来证 ...
随机推荐
- 人工神经网络,支持任意数量隐藏层,多层隐藏层,python代码分享
http://www.cnblogs.com/bambipai/p/7922981.html------误差逆传播算法讲解 人工神经网络包含多种不同的神经网络,此处的代码建立的是多层感知器网络,代码以 ...
- [TLSR8266] 1、搭建tlsr8266编译框架在win服务器中
前言 泰凌微TLSR8266蓝牙芯片的开发环境在win桌面系统中搭建起来比较简单,在其论坛SDK版块->Telink IDE中可以找到安装包,直接安装即可生成基于Eclipse的开发环境,及相关 ...
- python1数据链接总结
本节内容 列表.元组操作 字符串操作 字典操作 集合操作 文件操作 字符编码与转码 1. 列表.元组操作 列表是我们最以后最常用的数据类型之一,通过列表可以对数据实现最方便的存储.修改等操作 定义列表 ...
- 如何在嵌入式Linux上开发一个语音通信解决方案
开发一个语音通信解决方案是一个软件项目.既然是软件项目,就要有相应的计划:有多少功能,安排多少软件工程师去做,这些工程师在这一领域的经验如何,是否需要培训,要多长时间做完,中间有几个主要的milest ...
- .NET Core单文件发布静态编译AOT CoreRT
.NET Core单文件发布静态编译AOT CoreRT,将.NET Core应用打包成一个可执行文件并包含运行时. 支持Windows, MacOS and Linux x64 w/ RyuJIT ...
- 浅谈Android的广告欢迎界面(倒计时)
前些时候就是别人问我他的android APP怎么做一个广告的欢迎界面,就是过几秒后自动跳转到主界面的实现. 也就是下面这种类似的效果.要插什么广告的话你就换张图吧. 那么我就思考了下,就用了andr ...
- 表单中GET与POST的区别
1.本质 Get是向服务器发索取数据的一种请求,而Post是向服务器提交数据的一种请求. 2.服务器端获取值的方法 get方式提交的数据,服务器端使用request.QueryString获取变量的值 ...
- http常见状态码含义
200:请求成功 301:请求的资源已永久移动到新位置 302:请求的资源临时移动到新位置 304:请求内容无改变 401:未授权 403:禁止访问 404:文件未找到 500:服务器内部错误 501 ...
- Scrapy运行错误:ImportError: No module named win32api
需要安装pypiwin32,直接通过官网安装exe会出现很多错误,所以直接运行以下命令: pip install pypiwin32
- 【ASP.NET Core分布式项目实战】(三)整理IdentityServer4 MVC授权、Consent功能实现
本博客根据http://video.jessetalk.cn/my/course/5视频整理(内容可能会有部分,推荐看源视频学习) 前言 由于之前的博客都是基于其他的博客进行开发,现在重新整理一下方便 ...