Kruskal算法

首先了解这个算法是用来干嘛的
求最小生成树的算法主要是普里姆算法和克鲁斯卡尔算法,所以它和prim算法一样是用来用最小生成树的
克鲁斯卡尔(Kruskal)算法,是用来求加权连通图的最小生成树的算法。
基本思想:按照权值从小到大的顺序选择n-1条边,并保证这n-1条边不构成回路

问题背景

某城市新增7个站点(A,B,C,D,E,F,G),现在需要修路把7个站点连通

各个站点的距离用边线表示(权),比如A–B距离12公里

如何修路保证各个站点都能连通,并且总的修建公路总里程最短?

程序员必须会的基本算法7-Kruskal算法(库拉斯卡尔算法)_数组

解决

Kruskal算法的思路是这样的,
首先它是将所有的边按照权重从小到大进行了排序
然后从排序好的边中一条一条地选择加入到最小生成树中
第一步
选到的是E-F(2),判断有没有构成回路,因为E,F刚开始的顶点都是自己,所以没有构成回路,可以直接加入最小生成树数组中,设置E的顶点是F
第二步
选到的是C-D(3),C,D的顶点还是都是自己,直接加入,C的顶点是D
第三步
选的是D-E(4)边,D的顶点是D,E的顶点是F,直接加入,设置D的顶点是E
第四步
选择C-E,C的顶点是D,D的是E,E的是F,所以C的最终顶点是F,E的顶点也是F,构成回路,不能加入
下面的都差不多了,一直将所有的边都遍历一次,最小生成树就构建完成

代码解决

package basic;

import java.util.Arrays;

public class Kruskal
{
//number表示边的个数
public static int number;
public static char[] nodes;
public static final int INF=Integer.MAX_VALUE;
public static int[][] weight;

public static void main(String[] args)
{
weight= new int[][]{
/*A*//*B*//*C*//*D*//*E*//*F*//*G*/
/*A*/ { 0, 12, INF, INF, INF, 16, 14},
/*B*/ { 12, 0, 10, INF, INF, 7, INF},
/*C*/ { INF, 10, 0, 3, 5, 6, INF},
/*D*/ { INF, INF, 3, 0, 4, INF, INF},
/*E*/ { INF, INF, 5, 4, 0, 2, 8},
/*F*/ { 16, 7, 6, INF, 2, 0, 9},
/*G*/ { 14, INF, INF, INF, 8, 9, 0}};
nodes=new char[] {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
kruskal(nodes, weight);

}

public static void InitNumber()
{
for(int x=0;x<nodes.length;x++)
{
for(int y=x+1;y<nodes.length;y++)
{
if(weight[x][y]!=INF)
{
number++;
}
}
}
}
public static void kruskal(char[] nodes,int[][] weight)
{
//初始化number
InitNumber();

//返回结果的索引index,和保存结果的数组result
int index=0;
Edge[] result=new Edge[nodes.length-1];

//用于保存每一个节点在最小生成树中的结尾是什么
int[] ends=new int[number];

//然后想的是获取所有的边,然后将所有的边进行排序
Edge[] edges = getEdges();
Sort(edges);

//然后是判断每一条边看看是否是需要加入到最小生成树上面的
for(int x=0;x<number;x++)
{
//然后现在想判断的是这条边的两个节点的顶点是不是同一个顶点
int end1 = GetEnd(ends, edges[x].start);
int end2 = GetEnd(ends, edges[x].end);
if(end1!=end2)
{
ends[end1]=end2;
result[index++]=edges[x];
}
}
System.out.println("最小生成树为");
for(int i = 0; i < index; i++) {
System.out.println(result[i]);
}
}
public static int GetEnd(int[] ends,char node)
{
int index=-1;
for(int x=0;x<nodes.length;x++)
{
if(nodes[x]==node)
{
index=x;
break;
}
}
while(ends[index]!=0)
{
index=ends[index];
}
return index;
}

public static void Sort(Edge[] edges)
{
System.out.println("前:"+Arrays.toString(edges));
for(int x=0;x<edges.length-1;x++)
{
for(int y=0;y<edges.length-1-x;y++)
{
if(edges[y].weight>edges[y+1].weight)
{
Edge temp=edges[y];
edges[y]=edges[y+1];
edges[y+1]=temp;
}
}
}
System.out.println("后:"+Arrays.toString(edges));
}

public static Edge[] getEdges()
{
int index=0;
Edge[] edges=new Edge[number];
for(int x=0;x<nodes.length;x++)
{
for(int y=x+1;y<nodes.length;y++)
{
if(weight[x][y]!=INF)
{
edges[index++]=new Edge(nodes[x], nodes[y], weight[x][y]);
}
}
}
return edges;
}
}
/*
* 类Edge表示一条边,保存了start(边的开头字母),end(边的结尾字母),weight(边的权重)
*/
class Edge
{
char start;
char end;
int weight;
public Edge(char start, char end, int weight)
{
this.start = start;
this.end = end;
this.weight = weight;
}
@Override
public String toString()
{
return "<" + start + "," + end + ">=" + weight;
}
}