package com.kruskal;
import java.util.Arrays;
public class KruskalCase {
private int edgeNum;//边的个数
private char[] vertexs;//顶点个数
private int[][] matrix;//邻接矩阵
private static final int INF = Integer.MAX_VALUE;//表示连个顶点不能连通
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 print() {
System.out.println("邻接矩阵为:");
for (int i = 0; i < vertexs.length; ++i) {
for (int j = 0; j < vertexs.length; ++j) {
System.out.printf("%12d", matrix[i][j]);
}
System.out.println();
}
}
public static void main(String[] args) {
char[] vertexs = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
int[][] matrix = {
{0, 12, INF, INF, INF, 16, 24},
{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}};
KruskalCase kruskalCase = new KruskalCase(vertexs, matrix);
kruskalCase.print();
System.out.println("没有排序");
System.out.println(Arrays.toString(kruskalCase.getEdges()));
EData[] edges=kruskalCase.getEdges();
kruskalCase.sortEdges(edges);
System.out.println(Arrays.toString(edges));
kruskalCase.kruskal();
}
//对边进行排序,这里用冒泡排序
private void sortEdges(EData[] edges) {
for (int i = 0; i < edges.length - 1; ++i) {
for (int j = 0; j < edges.length - i - 1; ++j) {
if (edges[j].weight > edges[j + 1].weight) {
EData temp = edges[j];
edges[j] = edges[j + 1];
edges[j + 1] = temp;
}
}
}
}
//返回顶点对应的下标,如果找不到返回-1
private int getPosition(char ch) {
for (int i = 0; i < vertexs.length; ++i) {
if (ch == vertexs[i]) {
return i;
}
}
return -1;
}
//获取图中的边,放到EData[]数组,后面需要遍历数组
//通过邻接矩阵matrix获取
private 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的顶点的终点,用于判断两个顶点的终点是否相同
// ends:该数组记录了各个顶点对应的终点是哪一个, ends数组是在遍历过程中逐步形成的
// i: 表示传入的顶点对应的下标
// 返回的就是下标为i的顶点对应的终点的下标
// 我感觉这个函数的设计太刁了,你如果觉得一般,那你就是大佬
private int getEnd(int[] ends, int i){
//这个循环的设计太牛了,大佬写的太吊了
while (ends[i] !=0){
i=ends[i];
}
return i;
}
public void kruskal(){
int index=0; //表示最后结果数组中有多少条边, 理论行是n-1条
int[] ends= new int[edgeNum];// 用于保存"已有最小生成树"中每一个顶点在最下生成树中的终点
//创建结果数组,保存最小生成树
EData[] rets= new EData[edgeNum];
//获取图中所有边的集合 该示例一共12条边
EData[] edges= getEdges();
System.out.println(edges.length);
//按照边的权值排序
sortEdges(edges);
//遍历边的数组edges,将便添加到最小生成树,判断是否构成回路,如果没有构成,就加入到结果数组rets
for(int i=0;i<edges.length;++i){
//获取第i条边的第一个顶点(起点)
int p1=getPosition(edges[i].start);
//获取第i条边的第二个顶点
int p2=getPosition(edges[i].end);
//获取p1这个顶点在已有最小生成树中的终点
//第一次加入时,由于ends里面的值开始全为0.第一次相当于返回顶点下标,具体可以看getEnd()方法的具体实现
//也就是说如果第一次加入时,m是等于怕p1的
int m=getEnd(ends, p1);
//获取p1这个顶点在已有最小生成树中的终点
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]);
}
}
}
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 "EData[<" + start +","+end+">="+ weight+"]" ;
//return "EData{" + "start=" + start + ", end=" + end + ", weight=" + weight + '}';
}
}
有什么疑问,可以评论或私信我
更多数据结构问题代码实现请查看一下链接
JavaTest/denglianbin/src/com · 邓联斌/deng_study - 码云 - 开源中国 (gitee.com)