图-最小生成树算法之Kruskal及其Java实现

1.Kruskal算法

Kruskal算法基于贪心,因此它追求的是近似最优解,也就是说由Kruskal得出的生成树并不一定是最优解。

Kruskal算法求最小生成树的关键在于,每次选取图中权值最小(及贪心),并不会构成环的边,直到所有点都被囊括。一般,边的个数=点的个数-1。

如下无向图:

要找到最小生成树,克鲁斯卡尔算法的步骤如下:

 


 

2.Java实现

针对上述《算法导论》中的例子,有Java代码如下:

  1 import java.util.ArrayList;
  2 import java.util.Collections;
  3 import java.util.Iterator;
  4 
  5 //图类 无向图
  6 class G{
  7     ArrayList<V> vs=new ArrayList<V>();
  8     ArrayList<E> es=new ArrayList<E>();
  9     
 10     public void addV(V v) {
 11         vs.add(v);
 12     }
 13     
 14     public void add(E e) {
 15         es.add(e);
 16     }
 17 }
 18 
 19 //
 20 class V{
 21     String name;
 22     boolean isvisited=false;
 23     
 24     public V(String name) {
 25         this.name=name;
 26     }
 27 
 28     @Override
 29     public String toString() {
 30         return name;
 31     }
 32 }
 33 
 34 //
 35 class E{
 36     V v1;   //
 37     V v2;   //
 38     int Weight;   //权重
 39     boolean isvisited=false;
 40     
 41     public E(V v1,V v2,int Weight) {
 42         this.v1=v1;
 43         this.v2=v2;
 44         this.Weight=Weight;
 45     }
 46 
 47     @Override
 48     public String toString() {
 49         return "(" + v1 + ", " + v2 + ":" + Weight + ")";
 50     }
 51 }
 52 
 53 public class MinTree {
 54     //克鲁斯卡尔
 55     static void kruskal(G graph) {
 56         ArrayList<E> edges=graph.es;  //存储图的边集合
 57         ArrayList<E> forest=new ArrayList<E>();  //存放符合结果的边
 58         
 59         for(E e:edges) {   //遍历边集合,在初始化图的时候,边已按照权值排序
 60             ArrayList<E> testForest=refreshForest(forest);
 61             getEnd(testForest,e.v1,e.v2);
 62             if(endV) {  //判断是否形成回路
 63                 System.out.print(e);    //输出符合条件(不形成回路,权值最小)的边
 64                 forest.add(e);
 65             }
 66         }
 67     }
 68     
 69     //将图的边集合按权值排序
 70     static ArrayList<E> sortEdgeByWeight(ArrayList<E> es){
 71         for(int i=0;i<es.size();i++) {
 72             for(int j=0;j<es.size();j++) {
 73                 if(es.get(i).Weight<es.get(j).Weight) {
 74                     Collections.swap(es, i, j);
 75                 }
 76             }
 77         }
 78         return es;
 79     }
 80     
 81     static boolean endV=true;
 82     //判断新的边是否会和已有森林形成环:即得到目标点的末节点,由此判断两者是否相同,若相同则有环
 83     static void getEnd(ArrayList<E> testForest,V start,V end) {
 84         for(E e:testForest) {
 85             if(e.isvisited==false) {
 86                 if(e.v1.equals(start)) {
 87                     e.isvisited=true;
 88                     if(e.v2.equals(end)) {
 89                         endV=false;
 90                     }else {
 91                         getEnd(testForest,e.v2,end);
 92                     }
 93                 }else if (e.v2.equals(start)) {
 94                     e.isvisited=true;
 95                     if(e.v1.equals(end)) {
 96                         endV=false;
 97                     }else {
 98                         getEnd(testForest,e.v1,end);
 99                     }
100                 }
101             }
102         }
103     }
104     
105     //刷新森林:将森林中所有边标为未被查看,将endV标志也初始化一下
106     static ArrayList<E> refreshForest(ArrayList<E> forest) {
107         endV=true;
108         for(E e:forest) {
109             e.isvisited=false;
110         }
111         return forest;
112     }
113     
114     public static void main(String[] args) {
115         // TODO Auto-generated method stub
116         //创建点
117         V a=new V("a");
118         V b=new V("b");
119         V c=new V("c");
120         V d=new V("d");
121         V e=new V("e");
122         V f=new V("f");
123         V g=new V("g");
124         V h=new V("h");
125         V i=new V("i");
126         //创建点
127         
128         //创建边
129         E e0=new E(a,b,4);
130         E e1=new E(a,h,8);
131         E e2=new E(b,h,11);
132         E e3=new E(b,c,8);
133         E e4=new E(h,i,7);
134         E e5=new E(h,g,1);
135         E e6=new E(i,c,2);
136         E e7=new E(i,g,6);
137         E e8=new E(c,d,7);
138         E e9=new E(c,f,4);
139         E e10=new E(g,f,2);
140         E e11=new E(d,f,14);
141         E e12=new E(d,e,9);
142         E e13=new E(f,e,10);
143         //创建边
144         
145         //创建图
146         G graph=new G();
147         graph.addV(a);
148         graph.addV(b);
149         graph.addV(c);
150         graph.addV(d);
151         graph.addV(e);
152         graph.addV(f);
153         graph.addV(g);
154         graph.addV(h);
155         graph.addV(i);
156         ArrayList<E> es=new ArrayList<E>();
157         es.add(e0);
158         es.add(e1);
159         es.add(e2);
160         es.add(e3);
161         es.add(e4);
162         es.add(e5);
163         es.add(e6);
164         es.add(e7);
165         es.add(e8);
166         es.add(e9);
167         es.add(e10);
168         es.add(e11);
169         es.add(e12);
170         es.add(e13);
171         graph.es=sortEdgeByWeight(es);
172         //创建图
173         
174         //输出图
175         ArrayList<V> vertexs=graph.vs;
176         ArrayList<E> edges=graph.es;
177         Iterator iVertex=vertexs.iterator();
178         Iterator iEdge=edges.iterator();
179         System.out.println("点集合:");
180         while(iVertex.hasNext()) {
181             System.out.print(iVertex.next());
182         }
183         System.out.println();
184         System.out.println("边集合:");
185         while(iEdge.hasNext()) {
186             System.out.print(iEdge.next());
187         }
188         //输出图
189         
190         //最小生成树
191         //克鲁斯卡尔
192         System.out.println("");
193         System.out.println("克鲁斯卡尔:");
194         kruskal(graph);
195         //最小生成树
196 
197     }
198 
199 }

输出:

 

posted @ 2019-04-21 20:29  极地饮冰  阅读(900)  评论(0编辑  收藏  举报