在边赋权图中,权值总和最小的生成树称为最小生成树。构造最小生成树有两种算法,分别是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. Android动画(二)-属性动画

    我们在上一篇博客中,讨论了视图动画与帧动画.那么这节课则要讨论更复杂,更强大的Property animation(属性动画). 视图动画使用简单,但是功能也简单.(只有那四种功能).并且也不改变Vi ...

  2. ssh的action校验内容输出

    当form里为input类型时,如<input type="text" name="manager.name" />,则在对应的jsp中要使用< ...

  3. ping、traceroute原理

    说明:忘记从哪里拉的博文了,感谢! ping 用类型码为0的ICMP发请 求,受到请求的主机则用类型码为8的ICMP回应. ping程序来计算间隔时间,并计算有多少个包被送达.用户就可以判断网络大致的 ...

  4. flask入门

    一.Flask介绍(轻量级的框架,非常快速的就能把程序搭建起来) Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是 ...

  5. mysql安装及常见使用

    mysql的安装和使用 说明:mysql是一个多线程,多用户的sql数据库,有着高性能,高可靠性,易于实用性等特点. 安装的软件链接:https://pan.baidu.com/s/1smRLkoX ...

  6. 简单的vuex 的使用

    1. npm install vuex 2. 在src 下 新建文件夹 store (为什么是这个单词,vuex 是用来状态管理的,用储存一些组件的状态,取存贮之意),store 文件下 新建文件 i ...

  7. js,jq.事件代理(事件委托)复习。

    <ul id = "lists"> <li>列表1</li> <li>列表2</li> <li>列表3< ...

  8. I2S协议

    (一)I2S总线概述: 音响数据的采集.处理和传输是多媒体技术的重要组成部分.众多的数字音频系统已经进入消费市场,例如数字音频录音带.数字声音处理器.对于设备和生产厂家来说,标准化的信息传输结构可以提 ...

  9. T4模板生成代码。 数据实体层与数据仓储层。备注

    文件生成模板:TempleteManager.ttinclude <#@ assembly name="System.Core" #><#@ assembly n ...

  10. Java与算法之(11) - 合并排序

    天下事,合久必分,分久必合.合并排序的基本思想正是先分再合. 例如对3, 1这个数列排序,首先是分,分为3和1两个数列,然后再合并并排序.合并需要额外的辅助空间,即建立一个两个数列长度之和的空数组用于 ...