package kruscal;
import java.util.Arrays;
public class KruscalCase {
private int edgeNum; //边的个数
private char[] vertex; //顶点数组
private int[][] matrix; //邻接矩阵
//设置INF,表示两个节点不能连通
private static final int INF=Integer.MAX_VALUE;
public static void main(String[] args) {
// TODO Auto-generated method stub
char[] vertex= {'A','B','C','D','E','F','G'};
int matrix[][]= {
{0,12,INF,INF,INF,16,14},
{12,0,10,INF,INF,7,INF},
{INF,10,0,3,5,6,INF},
{INF,INF,3,0,4,INF,INF},
{INF,INF,5,4,0,2,8},
{16,7,6,INF,2,0,9},
{14,INF,INF,INF,8,9,0}
};
//创建KruskcalCase实例对象
KruscalCase kruscalCase=new KruscalCase(vertex,matrix);
//输出构建的
kruscalCase.print();
kruscalCase.kruskal();
}
//构造器
public KruscalCase(char[] vertex,int[][] matrix) {
//初始化顶点数和边的个数
int vlen=vertex.length;
//初始化顶点,this.vertex=vertex;
//这里采用复制的方式
this.vertex=new char[vlen];
for(int i=0;i<vertex.length;i++) {
this.vertex[i]=vertex[i];
}
//初始化边,可采用this.matrix=matrix;
//这里同样采用复制
this.matrix=new int[vlen][vlen];
for(int i=0;i<vertex.length;i++) {
for(int j=0;j<vertex.length;j++) {
this.matrix[i][j]=matrix[i][j];
}
}
//统计边的条数
for(int i=0;i<vlen;i++) {
for(int j=i+1;j<vlen;j++) {
if(this.matrix[i][j]!=INF) {
edgeNum++;
}
}
}
}
public void kruskal() {
int index=0; //表示最后结果数组的索引
int[] ends=new int[edgeNum]; //表示已生成的"最小生成树"中的每个顶点在最小生成树中的终点
//创建结果数组,保存最后的最小生成树
EData[] rets=new EData[edgeNum];
//获取图中所有的边的集合
EData[] edges=getEdges();
System.out.println("图的边的集合="+Arrays.toString(edges)+"共"+edges.length);
//按照边的权值大小从小到大排序
sortEdges(edges);
//遍历edges数组,将边添加到最小生成树中时,判断准备加入的边是否形成了回路,如果没有,就加入rets,否则不能加入
for(int i=0;i<edgeNum;i++) {
//获取第i条边的第一个顶点
int p1=getPosition(edges[i].start);
//获取第i条边的第二个顶点
int p2=getPosition(edges[i].end);
//获取p1顶点在已有最小生成树的终点
int m=getEnd(ends,p1);
//获取p2顶点在已有最小生成树的终点
int n=getEnd(ends,p2);
//是否构成回路
if(m!=n) {
ends[m]=n;
rets[index++]=edges[i];
}
}
//统计并打印"最小生成树",输出rets
System.out.println("最小生成树为:");
for(int i=0;i<index;i++) {
System.out.println(rets[i]);
}
}
//打印邻接矩阵
public void print() {
for(int i=0;i<vertex.length;i++) {
for(int j=0;j<vertex.length;j++) {
System.out.printf("%12d",matrix[i][j]);
}
System.out.println(); //换行
}
}
/**
* 功能:对边进行排序处理,冒泡排序
* @param edges 边的集合
*/
private void sortEdges(EData[] edges) {
for(int i=0;i<edges.length-1;i++) {
for(int j=0;j<edges.length-1-i;j++) {
if(edges[j].weigh>edges[j+1].weigh){
EData temp=edges[j];
edges[j]=edges[j+1];
edges[j+1]=temp;
}
}
}
}
/**
*
* @param ch 顶点的值,比如'A','B'
* @return 返回ch顶点的下标,如果找不到就返回-1
*/
private int getPosition(char ch) {
for(int i=0;i<vertex.length;i++) {
if(vertex[i]==ch) {
return i;
}
}
return -1;
}
/**
* 功能:获取图中的边,放到EData[]数组中,后面我们需要遍历数组
* 通过matrix邻接矩阵获取
* EData形式:[['A','B',12],['B','F',7],....]
* @return
*/
private EData[] getEdges() {
int index=0;
EData[] edges=new EData[edgeNum];
for(int i=0;i<vertex.length;i++) {
for(int j=i+1;j<vertex.length;j++) {
if(matrix[i][j]!=INF) {
edges[index++]=new EData(vertex[i],vertex[j],matrix[i][j]);
}
}
}
return edges;
}
/**
* 功能:获取下标为i的顶点的终点,用于后面判断两个顶点的终点是否相同
* @param ends 数组记录就是遍历过程中每次各个顶点的终点,动态的
* @param i 表示传入顶点的对应下标
* @return 返回的是终点对应的下标
*/
private int getEnd(int[] ends,int i) {
while(ends[i]!=0) {
i=ends[i];
}
return i;
}
}
class EData{
char start;
char end;
int weigh;
//构造器
public EData(char start,char end,int weigh) {
this.start=start;
this.end=end;
this.weigh=weigh;
}
@Override
public String toString() {
return "EData [<" + start + "," +end+ ">=" + weigh + "]";
}
}