在边赋权图中,权值总和最小的生成树称为最小生成树。构造最小生成树有两种算法,分别是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算法的更多相关文章

  1. 最小生成树之Prim算法和Kruskal算法

    最小生成树算法 一个连通图可能有多棵生成树,而最小生成树是一副连通加权无向图中一颗权值最小的生成树,它可以根据Prim算法和Kruskal算法得出,这两个算法分别从点和边的角度来解决. Prim算法 ...

  2. 【数据结构】最小生成树之prim算法和kruskal算法

    在日常生活中解决问题经常需要考虑最优的问题,而最小生成树就是其中的一种.看了很多博客,先总结如下,只需要您20分钟的时间,就能完全理解. 比如:有四个村庄要修四条路,让村子能两两联系起来,这时就有最优 ...

  3. 最小生成树之 prim算法和kruskal算法(以 hdu 1863为例)

    最小生成树的性质 MST性质:设G = (V,E)是连通带权图,U是V的真子集.如果(u,v)∈E,且u∈U,v∈V-U,且在所有这样的边中, (u,v)的权c[u][v]最小,那么一定存在G的一棵最 ...

  4. 最小生成树(prim算法和kruskal算法)

    学习博客:https://www.cnblogs.com/zhangming-blog/p/5414514.html 其实就是加点法:从不属于这个集合的点中找从本集合可以找到的最小边,加入本集合 看代 ...

  5. 转载:最小生成树-Prim算法和Kruskal算法

    本文摘自:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html 最小生成树-Prim算法和Kruskal算法 Prim算 ...

  6. 最小生成树——Prim算法和Kruskal算法

    洛谷P3366 最小生成树板子题 这篇博客介绍两个算法:Prim算法和Kruskal算法,两个算法各有优劣 一般来说当图比较稀疏的时候,Kruskal算法比较快 而当图很密集,Prim算法就大显身手了 ...

  7. 最小生成树Prim算法和Kruskal算法

    Prim算法(使用visited数组实现) Prim算法求最小生成树的时候和边数无关,和顶点树有关,所以适合求解稠密网的最小生成树. Prim算法的步骤包括: 1. 将一个图分为两部分,一部分归为点集 ...

  8. Prim算法和Kruskal算法

       Prim算法和Kruskal算法都能从连通图找出最小生成树.区别在于Prim算法是以某个顶点出发挨个找,而Kruskal是先排序边,每次选出最短距离的边再找. 一.Prim(普里姆算法)算法: ...

  9. Prim算法和Kruskal算法的正确性证明

    今天学习了Prim算法和Kruskal算法,因为书中只给出了算法的实现,而没有给出关于算法正确性的证明,所以尝试着给出了自己的证明.刚才看了一下<算法>一书中的相关章节,使用了切分定理来证 ...

随机推荐

  1. vue2.0表单事件的绑定

    v-model 1.input type="text" <template> <div id="app"> <label for= ...

  2. Zabbix 单位换算

    直接举一例子,然后再举一反三: 如图: 单位B 则基数为1024(倍数) 我性能参数为KB单位,我们则把单位转换成和我们计数器 保持一致的单位即可,一致后,zabbix 后面会自己准换成自己想要的显示 ...

  3. TurnipBit开发板掷骰子小游戏DIY教程实例

    转载请以链接形式注明文章来源(MicroPythonQQ技术交流群:157816561,公众号:MicroPython玩家汇) 0x00前言 下面带大家用TurnipBit开发板实现一个简单的小游戏- ...

  4. RGB颜色 对照表

      来自为知笔记(Wiz)

  5. WPF自定义Window样式(1)

    1. 引言 WPF是制作界面的一大利器.最近在做一个项目,用的就是WPF.既然使用了WPF了,那么理所当然的,需要自定义窗体样式.所使用的代码是在网上查到的,遗憾的是,整理完毕后,再找那篇帖子却怎么也 ...

  6. 巧用CSS居中未知高度的块元素

    在网页中让一个未知高度的块元素水平垂直居中是一个老生常谈的问题,但是总是有些特殊场景让你无法得心应手的实现居中,本文介绍几种常用的经典的居中方法,总有一种适合你! 1. position .paren ...

  7. Python笔记(二):列表+列表数据处理+函数

    #才疏学浅,难免有不恰当之处,请不吝指正,谢谢. #适合初学者. 列表的数据自下而上堆放(形成一个堆栈),类似于其他编程语言的数组.例如: user = ["张三","李 ...

  8. 从Unity中的Attribute到AOP(六)

    本文将重点对Unity剩下常用的Attribute进行讲解,其他不常用的Attribute各位可以自行去官方文档查阅. 首先是UnityEngine命名空间下的. ColorUsage,这个主要作用于 ...

  9. smtplib 报错501

    昨天用stmplib写了一个自动发送的邮件的小程序. 之前能够正常运行,到了下午发现报错. 报错信息:smtplib.SMTPSendRefused(501,b'\xc7\xeb\xb5\xc7\xc ...

  10. uboot各种目录下的文件作用

    uboot下载地址:http://ftp.denx.de/pub/u-boot/ 1.目录分布 2.目录结构变化: u-boot-2010.03及以前版本├── api                ...