克鲁斯卡尔算法
算法介绍
- 克鲁斯卡尔算法:是用来求加权连通图的最小生成树的算法
- 基本思想:按照权值从小到大的顺序选择n-1条边,并保证这n-1条边不构成回路
- 具体做法: 首先构造一个只包含n个顶点的森林,然后依权值从小到大从连通网中选择边加入到森林,并使得森林中不产生回路,值只森林变成一颗树为止
代码实现
package L十大算法.Kruskal;
import com.sun.javafx.geom.Edge;
import java.util.Arrays;
/**
* @Author Zhou jian
* @Date 2020 ${month} 2020/1/15 0015 17:16
*/
public class KruskalAlgrothim {
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}};
//创建克鲁斯卡尔对象的实例
KruskalAlgrothim kruskalCase = new KruskalAlgrothim(vertexs,matrix);
// //输出构建的对象
// kruskalCase.print();
//
// EData[] edges = kruskalCase.getEdges();
// System.out.println("位排序"+Arrays.toString(edges));
// kruskalCase.sortEdges(edges);
// System.out.println("排完顺序"+Arrays.toString(edges));
kruskalCase.kruskal();
}
public KruskalAlgrothim(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.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("临街矩阵为\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();
}
}
//对边进行排序处理:冒泡排序
/**
* @param edges 边的集合
*
*/
private void sortEdges(EData[] edges){
for(int i=0;i<edges.length;i++){
for(int j=0;j<edges.length-1-i;j++){
if(edges[j+1].weight<edges[j].weight){
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<vertexs.length;i++){
if(vertexs[i]==ch){//找到
return i;
}
}
return -1;
}
/**
* 功能:获取图中边,放到EData[] 数组中,后面需要遍历该数组
* 通过martix领结矩阵来得到
* EData[]形式 [['A','B',12],['B','F',7],...............]
* @return
*/
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 &&matrix[i][j]!=0){//当两点构成一条边时
edges[index++]= new EData(vertexs[i],vertexs[j],matrix[i][j]);
}
}
}
return edges;
}
/**
* 获取下标为i的顶点的终点:用于判断两个顶点的终点是否仙童
* @param ends 记录了各个顶点对应的终点是哪个是在遍历的过程中逐步加入的;ends是在遍历过程中逐步形成的
* @param i 表示传入顶点对应的下标
* @return 返回的就是下标为i的这个顶点对应的终点的下标
* 将边添加到最小生成树中时,怎么样判断是否形成了回路
* ----->
* 记录顶点在最小生成树的终点,顶点的终点是在“ 最小生成树中与他连通的最大顶点,然后每次需要将一条边添加到最小生成树时
* 判断该边的两个顶点的终点是否重合,重合的haul会构成回路“
*
*/
private int getEnd(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[] res = new EData[edgeNum];
//获取原始图中所有的边的集合
EData[] edges = getEdges();
//按照边的权值大小进行排序(从小到大——
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;//设置m在最小生成树中的终点
res[index++]= edges[i];//有一条边加入到results
}
}
//统计并打印“最小生成树" ,输出res
System.out.println("最小生成树权威"+Arrays.toString(res));
}
}
//创建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;
}
//重新toString便于输出
@Override
public String toString() {
return "EData{" +
"start=" + start +
", end=" + end +
", weight=" + weight +
'}';
}
}