package com.atguigu.kruskal;
import java.util.Arrays;
/**
* @author
* @create 2022-08-19-16:07
*/
public class KruskalAlgorithm {
private int edgeNum;//记录边的个数
private char[] vertexs;//顶点数组
private int[][] matrix;//邻接矩阵
//使用INF表示两个顶点不能联通
private static final int INF = Integer.MAX_VALUE;
public static void main(String[] args) {
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}};
KruskalAlgorithm kruskalAlgorithm = new KruskalAlgorithm(vertexs, matrix);
//输出构建的图
kruskalAlgorithm.printMatrix();
EData[] edges = kruskalAlgorithm.getEdges();
//未排序前
System.out.println("排序前" + Arrays.toString(edges));
//排序
kruskalAlgorithm.sortEdge(edges);
System.out.println("排序后" + Arrays.toString(edges));
System.out.println("================");
kruskalAlgorithm.kruskal();
}
//构造器
public KruskalAlgorithm(char[] vertexs, int[][] matrix) {
//初始化顶点数和边的个数
int vlen = vertexs.length;
//初始化顶点,复制拷贝的方式
this.vertexs = new char[vlen];
for (int i = 0; i < vertexs.length; i++) {
this.vertexs[i] = vertexs[i];
}
// //或者可以用下面方式
// this.vertexs = vertexs;
//初始化边
this.matrix = new int[vlen][vlen];
//采用拷贝的方式赋值
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[0].length; j++) {
this.matrix[i][j] = matrix[i][j];
}
}
//统计边的数量
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[0].length; j++) {
if (this.matrix[i][j] != INF && this.matrix[i][j] != 0) {
edgeNum++;
}
}
}
}
//打印邻接矩阵
public void printMatrix() {
System.out.println("打印邻接矩阵");
//方法1:
// for (int[] line : this.matrix) {
// System.out.println(Arrays.toString(line));
//
// }
//方法2:
for (int i = 0; i < this.matrix.length; i++) {
for (int j = 0; j < this.matrix[0].length; j++) {
System.out.printf("%13d", this.matrix[i][j]);
}
System.out.println();
}
}
//对边进行排序
/**
* @param edges 边的集合
*/
private void sortEdge(EData[] edges) {
for (int i = 0; i < edges.length - 1; 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 返回顶点在vertexs数组中的下标,若不存在,则返回-1
*/
private int getPosition(char ch) {
for (int i = 0; i < vertexs.length; i++) {
if (vertexs[i] == ch) {
return i;
}
}
//找不到返回-1
return -1;
}
/**
* 功能:将边对象作为EData[]数组的一个元素存放起来
* 通过邻接矩阵matrix来获取
* 如:[['B','F',12],['A','B',3],...]
*
* @return
*/
private EData[] getEdges() {
int index = 0;
EData[] edges = new EData[edgeNum];
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[0].length; j++) {
if (matrix[i][j] != INF && matrix[i][j] != 0) {
edges[index++] = new EData(vertexs[i], vertexs[j], matrix[i][j]);
}
}
}
return edges;
}
/**
* @param ends ends[i]记录了每个顶点对应终点是哪个,ends数组在遍历过程中逐步形成
* @param i 传入顶点对应的下标
* @return 返回下标为i的顶点的终点
* 用于后续判断两个顶点终点是否相同
*/
private int getEnds(int[] ends, int i) {
while (ends[i] != 0) {
i = ends[i];
}
return i;
}
//克鲁斯卡尔算法
public void kruskal() {
int index = 0;//用于最后结果的数组索引
int[] ends = new int[edgeNum];//用于保存在已有最小生成树中每个顶点的终点
//用于存放最后结果
EData[] results = new EData[edgeNum];
EData[] edges = getEdges();//拿到图中所有的边 12条
//排序
sortEdge(edges);
//遍历edges数组,通过判断边来判断该边是否加入到结果数组中
for (int i = 0; i < edges.length; i++) {
//得到第i个边的第一个顶点的下标
int p1 = getPosition(edges[i].start);
//得到第i个边的第二个顶点的下标
int p2 = getPosition(edges[i].end);
//得到第i个边的第一个顶点的终点
int m = getEnds(ends, p1);
//得到第i个边的第二个顶点的终点
int n = getEnds(ends, p2);
//判断是否其终点相同
if (m != n) {//如果重点不相同则将该边加入到结果数组中
ends[m] = n;//设置m在已有生成树的重点为n
// ends[n]=n;//这句没有必要写,在getEnds()方法中就已经实现了这个要求
results[index++] = edges[i];//有一条边加入数组中
}
}
//统计并打印最小生成树,输出result数组
System.out.println("最小生成树为=");
for (int i = 0; i < index; i++) {
System.out.println(results[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;
}
//为了方便后续输出边的信息,重写toString方法
@Override
public String toString() {
return "EData{" +
"start=" + start +
", end=" + end +
", weight=" + weight +
'}';
}
}
数据结构和算法学习之克鲁斯卡尔(kruskal)算法
最新推荐文章于 2022-11-14 17:20:26 发布