package kruskal;
import java.util.Arrays;
public class KruskalCase {
private int edgeNum; //顶点个数
private char [] vertexs; //顶点数组
private int[][] matrix;//邻接矩阵
//INF 表示不能连通
private static final int INF = Integer.MAX_VALUE;
public static void main(String[] args) {
// TODO Auto-generated method stub
char[] vertexs = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
int matrix[][] = {
/*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}};
KruskalCase krukalCase = new KruskalCase(vertexs,matrix);
krukalCase.print();
// EData[] edges = krukalCase.getEdges();
// System.out.println("排序前"+Arrays.toString(edges));
// krukalCase.sortEdge(edges);
// System.out.println("排序后"+Arrays.toString(edges));
krukalCase.kruskal();
}
public KruskalCase(char []vertexs,int [][]matrix) {
//初始化顶点数和边的个数
int vlen = vertexs.length;
//初始化顶点复制拷贝
this.vertexs = new char[vlen];
for(int i=0;i<vlen;i++) {
this.vertexs[i] =vertexs[i];
}
//初始化邻接矩阵
this.matrix = new int[vlen][vlen];
for(int i=0;i<vlen;i++) {
for(int j=0;j<vlen;j++) {
this.matrix[i][j] =matrix[i][j];
}
}
//统计边的条数
for(int i=0;i<vlen;i++) {
for(int j=i+1;j<vlen;j++) {
if(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));
//进行排序
sortEdge(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; //设置m在最小生成数中的终点
rets[index++]=edges[i]; //加入到最小生成树中
}
}
System.out.println("最小生成树:");
for(int i=0;i<index;i++) {
System.out.println(rets[i]);
}
}
public void print() {
System.out.println("邻接矩阵为:\n");
for(int i=0;i<vertexs.length;i++) {
for(int j=0;j<vertexs.length;j++) {
System.out.printf("%12d\t",matrix[i][j]);
}
System.out.println();
}
}
//对edge的集合进行排序 冒泡排序
public void sortEdge(EData[] edges) {
for(int i=0;i<edges.length;i++) {
for(int j=0;j<edges.length-1-i;j++) {
if(edges[j].weight>edges[j+1].weight) {
EData temp = edges[j];
edges[j] = edges[j+1];
edges[j+1] = temp;
}
}
}
}
/**
*
* @param ch 顶点的值比如 "A" "B"
* @return ch对应的顶点的下标
*/
public int getPosition(char ch) {
for(int i =0;i<vertexs.length;i++) {
if(vertexs[i]==ch) {
return i;
}
}
return -1;
}
/**
* EData的形式[["A","B",10],["B","F",7],....]
* @return
*/
public EData[] getEdges() {
int index =0;
EData [] edges = new EData[edgeNum];
for(int i=0;i<vertexs.length;i++) {
for(int j=i+1;j<vertexs.length;j++) {
if(matrix[i][j] !=INF) {
edges[index++] =new EData(vertexs[i],vertexs[j],matrix[i][j]);
}
}
}
return edges;
}
/**
* 功能:获取下标为i的顶点的终点下标,用于后面判断两个顶点的终点是否相同
* @param ends: 数组记录了各个顶点对应的终点是哪个,ends在数组遍历的过程中逐步形成,
* @param i: 对应传入数组的下标
* @return 返回的是下标为i对应的顶点的终点
*/
private int getEnd(int[] ends,int i) {//注意如果ends[i]=0则返回i
while(ends[i]!=0) {
i=ends[i];
}
return i;
}
}
//EData类对象的实例就是表示一条边
class EData{
char start;
char end;
int weight;
public EData(char start,char end, int weight) {
this.start = start;
this.end = end;
this.weight = weight;
}
@Override
public String toString() {
return "<" + start + "," + end + ">" + weight;
}
}