java实现最小生成树的prim算法和kruskal算法

算法   2015-02-14 12:21:43 发布
您的评价:
     
0.0
收藏     3收藏
文件夹
标签
(多个标签用逗号分隔)

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

java实现最小生成树的prim算法和kruskal算法

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

java实现最小生成树的prim算法和kruskal算法

这样构建的最小生成树的权值总和最小,为17


在构建最小生成树中,一般有两种算法,prim算法和kruskal算法

在prim算法中,通过加入最小邻接边的方法来建立最小生成树算法。首先构造一个零图,在选一个初始顶点加入到新集合中,然后分别在原先的顶点集合中抽取一个顶点,使得构成的边为权值最小,然后将该笔边加入到图中,并将抽出的顶点加入到新集合中,重复这个过程,知道新集合等于原先的集合。

代码如下:

package 最小生成树;
/*
 * 最小生成树prim算法,加入最小邻接边生成最小生成树。
 * 首先构造一个零图,选择一个初始点加入到集合中,
 * 然后分别从原来顶点的集合中抽取一个顶点,
 * 选择的标准是构造成的树的权值最小,
 * 循序渐进最终生成一棵最小生成树
 */
public class prim {
 /**
  * @author 刘雁冰
  * @date 2015-02-13 20:23
  */
 
 /*
  * 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);
 }
}


测试结果如下:

java实现最小生成树的prim算法和kruskal算法

在kruskal算法中,根据边的权值以递增的方式逐渐建立最小生成树。具体操作是:将赋权图每个顶点都看做森林,然后将图中每条邻接边的权值按照升序的方式进行排列,接着从排列好的邻接边表中抽取权值最小的边,写入该边的起始顶点和结束顶点,连接顶点将森林构成树,然后读取起始结束顶点的邻接边,优先抽取权值小的邻接边,继续连接顶点将森林构成树。添加邻接边的要求是加入到图中的邻接边不构成回路。如此反复进行,直到已经添加n-1条边为止。

代码如下:

package 最小生成树;
import java.util.ArrayList;
import java.util.Scanner;
/*
 * 最小生成树kruskal算法:首先将每个顶点作为一棵森林,升序比较该顶点的邻接边,
 * 每次取最小权值的邻接边,将该邻接边连接的顶点与原先顶点构成一棵树,接着寻找
 * 下一个顶点,继续按照邻接边权值升序进行比较,取权值最小的构成树...
 * 
 * 该类用一个Edge类构成一个邻接边的信息,包括邻接边的起始顶点与结束顶点,权值。
 * 用类Edge创建对象,录入对象信息,按照对象的权值进行比较,符合条件的对象加入
 * 到链表中,最终按照链表顺序输出最小生成树。
 */
public class kruskal {
 /**
  * @author 刘雁冰
  * @date 2015-02-13 20:23
  */
 
 /*
  * 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算法

来自:http://my.oschina.net/luckid/blog/378552

扩展阅读

太惊艳了,原来算法可视化后可以这么艺术(多gif图)
最小生成树(普利姆算法、克鲁斯卡尔算法)
Kruskal 最小生成树算法
最小生成树——Kruskal(克鲁斯卡尔)算法
K最近邻(KNN)算法的java实现

为您推荐

Kruskal 最小生成树算法
最小生成树——Kruskal(克鲁斯卡尔)算法
算法题:顶点覆盖问题
最短路径算法
Android SwipeBackLayout源码解析

更多

算法
相关文档  — 更多
相关经验  — 更多
相关讨论  — 更多