克鲁斯卡尔算法(Kruskal's algorithm)是两个经典的最小生成树算法的较为简单理解的一个。这里面充分体现了贪心算法的精髓。算法如下:
假设T中的边和顶点均涂成红色,其余边为白色。开始时G中的边均为白色。
1)将所有顶点涂成红色;
2)在白色边中,挑选一条权最小的边,使其与红色边不形成圈,将该白色边涂红;
3)重复2)直到有n-1条红色边,这n-1条红色边便构成最小生成树T的边集合。
注意到在算法执行过程中,红色顶点和红色边会形成一个或多个连通分支,它们都是G的子树。一条边与红色边形成圈当且仅当这条边的两个端点属于同一个子树。因此判定一条边是否与红色边形成圈,只需判断这条边的两端点是否属于同一个子树。
上述判断可以如此实现:给每个子树一个不同的编号,对每一个顶点引入一个标记t,表示这个顶点所在的子树编号。当加入一条红色边,就会使该边两端点所在的两个子树连接起来,成为一个子树,从而两个子树中的顶点标记要改变成一样。综上,可将Kruskal算法细化使其更容易计算机实现。
我的实现结果如下:(200个节点)
java部分代码如下:
public static void kruskal(Graph g) { // 每个顶点加编号 int[] parent = new int[g.MAX_VERTEX ]; for (int i = 0; i < g.MAX_VERTEX; i++) { parent[i] = i; } // 找到n-1条边,既满足条件 while (result.size() < (g.MAX_VERTEX-1) ) { // 取最小边 double min = MOUSTMAX; int jtemp=0; int i = 0; for(int k=0;k<g.MAX_VERTEX;k++){ for (int j = 0; j < g.MAX_VERTEX; j++) { // System.out.println("-------------"+k+"--"+j + "parent[" + k + "]--"+parent[k]+"parent[" + j+"]" +parent[j] + "--"+g.L1_Matrix[k][j] + "min" + min); if ((parent[k] != parent[j] ) && g.L1_Matrix[k][j] < min) { min = g.L1_Matrix[k][j]; jtemp = j; i=k; } } } int jj = parent[i]; int kk = parent[jtemp]; proc.add("------选中结点 "+i+" 与结点 "+jtemp + " ,路径长度:" + g.L1_Matrix[i][jtemp]); //判断该边的两个端点是否在同一个子树中: // 不在:将该边加入结果集 // 在:继续循环 if (kk != jj) { int tempi = parent[i]; //将新找到的边的顶点与以前的顶点标志值设为一样,注意要把以前的顶点相连的顶点都要同步改变值 for(int j = 0; j<parent.length;j++){ if(parent[j] == tempi ) parent[j] = parent[jtemp]; } //取出已经加入的边 boolean temp = true; for(Vertex[] v:result){ if(v[0] == g.vertexList[i] && v[1] ==g.vertexList[jtemp]){ temp = false; } if(v[1] == g.vertexList[i] && v[0] ==g.vertexList[jtemp]){ temp = false; } } if(temp){ result.add(new Vertex[] { g.vertexList[i],g.vertexList[jtemp] } ); } //将已找到的边,权值设为最大 g.L1_Matrix[i][jtemp] = MOUSTMAX; } } }
---------------------------------------------------------
参见:http://home.ustc.edu.cn/~chh1990/win/
-------------------------------------------------------------------