用于最小生成树的Prim算法实现

来源:互联网 发布:36o隐私保险箱数据恢复 编辑:程序博客网 时间:2024/06/04 18:53

Prim算法,同Kruskal算法一样,也是解决最小生成树的算法。在讲这个算法前,我们先来看看其他的一些概念。

什么是割?在无向图中,割指的是对图的一种划分。当一条边(u,v)的一个顶点属于S,另一个顶点属于V-S,则我们称(u,v)边通过割(S,V-S)。如果一个边的集合A中没有任何一条边通过割,则我们称该割不妨害边集A。如果某条边的权值在通过某个割的所有边中是最小的,则称该边是通过该割的一条轻边。

Prim算法的基本思想就是不断的寻找通过一条割的轻边,这个割是指当前最小生成树所组成的点集S和图中不在最小生成树中的点集(V-S)所形成的一种图的划分,然后将所找到的轻边添加到最小生成树中。我们使用最小优先队列来快速的寻找通过某个割的轻边。当然,我们在寻找轻边的时候要检查该边的两个顶点是否已经在最小生成树中,如果在的话,我们就不需要再将这条边添加到最小生成树的边集了,因为这两个端点已经是连通着的了。

代码实现如下所示:

package com.chapter4;

//用于解决最小生成树问题的Prim算法(延时版本)

import java.util.Queue;

import java.util.LinkedList;

public class LazyPrimMST {

         privateQueue<Edge> mst;

         private boolean[]marked;

         private doubletotalweight;

         privateMinPriorityQueue<Edge> mpq;

        

         publicLazyPrimMST(EdgeWeightedGraph G)

         {

                   int V=G.V();

                   mst=newLinkedList<Edge>();

                   marked=newboolean[V];

                   mpq=newMinPriorityQueue<Edge>();

                   for(inti=0;i<V;i++)

                   {

                            if(!marked[i])

                                     prim(G,i);

                   }

         }

         private voidprim(EdgeWeightedGraph G,int s)

         {

                   scan(G,s);

                   while(!mpq.isEmpty())

                   {

                            Edgee=mpq.deleteMin();

                            System.out.println("从优先队列中移除"+e);

                            intv=e.either(),w=e.other(v);

                            assertmarked[v]||marked[w];

                            if(marked[v]&&marked[w])continue;

                            mst.add(e);

                            System.out.println("向最小生成树的边集合中加入"+e);

                            totalweight+=e.weight();

                            if(!marked[v])scan(G,v);

                            if(!marked[w])scan(G,w);

                   }

         }

        

         private voidscan(EdgeWeightedGraph G,int v)

         {

                   assert!marked[v];

                   marked[v]=true;

                   for(Edgee:G.adj(v))

                   {

                            if(!marked[e.other(v)])

                            {

                                     mpq.insert(e);

                                     System.out.println("向优先队列中加入"+e);

                            }

                   }

         }

        

         public doubletotalWeight(){return totalweight;}

        

         public StringtoString()

         {

                   StringBuildersb=new StringBuilder();

                   sb.append("最小生成树的边信息:\n");

                   for(Edgee:mst)

                   {

                            sb.append(e.toString()+"\n");

                   }

                   sb.append(String.format("权值和为:%.5f",totalweight));

                   returnsb.toString();

         }

        

         public static voidmain(String[] args) {

                   // TODOAuto-generated method stub

                   In in=newIn("tinyEWG.txt");

                   EdgeWeightedGraphgraph=new EdgeWeightedGraph(in);

                   LazyPrimMSTsample=new LazyPrimMST(graph);

                   System.out.println(sample);

         }

}

运行结果如下所示:

 

向优先队列中加入0--7[0.16000]

向优先队列中加入0--4[0.38000]

向优先队列中加入0--2[0.26000]

向优先队列中加入6--0[0.58000]

从优先队列中移除0--7[0.16000]

向最小生成树的边集合中加入0--7[0.16000]

向优先队列中加入4--7[0.37000]

向优先队列中加入5--7[0.28000]

向优先队列中加入1--7[0.19000]

向优先队列中加入2--7[0.34000]

从优先队列中移除1--7[0.19000]

向最小生成树的边集合中加入1--7[0.19000]

向优先队列中加入1--5[0.32000]

向优先队列中加入1--2[0.36000]

向优先队列中加入1--3[0.29000]

从优先队列中移除0--2[0.26000]

向最小生成树的边集合中加入0--2[0.26000]

向优先队列中加入2--3[0.17000]

向优先队列中加入6--2[0.40000]

从优先队列中移除2--3[0.17000]

向最小生成树的边集合中加入2--3[0.17000]

向优先队列中加入3--6[0.52000]

从优先队列中移除5--7[0.28000]

向最小生成树的边集合中加入5--7[0.28000]

向优先队列中加入4--5[0.35000]

从优先队列中移除1--3[0.29000]

从优先队列中移除1--5[0.32000]

从优先队列中移除2--7[0.34000]

从优先队列中移除4--5[0.35000]

向最小生成树的边集合中加入4--5[0.35000]

向优先队列中加入6--4[0.93000]

从优先队列中移除1--2[0.36000]

从优先队列中移除4--7[0.37000]

从优先队列中移除0--4[0.38000]

从优先队列中移除6--2[0.40000]

向最小生成树的边集合中加入6--2[0.40000]

从优先队列中移除3--6[0.52000]

从优先队列中移除6--0[0.58000]

从优先队列中移除6--4[0.93000]

最小生成树的边信息:

0--7[0.16000]

1--7[0.19000]

0--2[0.26000]

2--3[0.17000]

5--7[0.28000]

4--5[0.35000]

6--2[0.40000]

权值和为:1.81000

(说明:程序中需要的其他一些类可以在“用于最小生成树的Kruskal算法实现”一文中查到,在这篇文章中不在重复!)

文章链接: http://blog.csdn.net/andamajing/article/details/8702179点击打开链接

原创粉丝点击