Kruskal算法实现

1.主要思想

	和Prim算法不同,克鲁斯卡尔算法是依次遍历图中的边,按照边的权值进行构造最小生成树,关键是要判断每次加入的边和已经加入的边是否构成回路(这是关键),最后生成了一个有(vertex-1)条边的最小生成树。

2.代码实现

1.克鲁斯卡尔类
package KruskalAlgothm;

import javax.swing.*;
import java.util.Arrays;

public class Kruskal {
    // 成员变量
    private int edgeNum; // 图的边的个数
    private char[] vertex; // 存放顶点的一维数组
    private int[][] Link_Array; // 图的邻接矩阵
    private static int Max = Integer.MAX_VALUE; // 当两个顶点不能直达时,设置其权值为无穷大,这里使用int最大值表示

    // 构造方法
    public Kruskal() {
    }

    public Kruskal(char[] vertexs, int[][] Link_Array) {
        // 初始化顶点
        this.vertex = new char[vertexs.length]; // 动态初始化
        for (int i = 0; i < vertexs.length; i++) { // 静态初始化
            this.vertex[i] = vertexs[i];
        }
        // 初始化边
        this.Link_Array = new int[vertex.length][vertex.length]; // 动态初始化
        for (int i = 0; i < vertex.length; i++) {     // 静态初始化
            for (int j = 0; j < vertex.length; j++) {
                this.Link_Array[i][j] = Link_Array[i][j];
            }
        }
        // 统计边
        for (int i = 0; i < vertex.length; i++) {
            for (int j = 0; j < vertex.length; j++) {
                if (this.Link_Array[i][j] != Max) {
                    edgeNum++;
                }
            }
        }
    }

    // 成员方法

    // 打印邻接矩阵
    public void print_LinkArray() {
        System.out.println("邻接矩阵为:");
        for (int row = 0; row < vertex.length; row++) {
            for (int line = 0; line < vertex.length; line++) {
                System.out.printf("%12d", Link_Array[row][line]);
            }
            System.out.println();
        }
    }

    // 对边进行排序 --> 冒泡
    public void SortEdge(Edge[] edges) {
        for (int i = 0; i < edgeNum - 1; i++) {
            for (int j = 0; j < edgeNum - 1 - i; j++) {
                if (edges[j].value > edges[j + 1].value) {
                    Edge temp = edges[j + 1];
                    edges[j + 1] = edges[j];
                    edges[j] = temp;
                }
            }
        }
    }

    // 获取顶点对应的下标
    public int getVertex_Index(char v) {
        for (int i = 0; i < vertex.length; i++) {
            if (vertex[i] == v) {
                return i;
            }
        }
        return -1;
    }

    // 将图中的边存放在一个数组中,方便以后遍历(克鲁斯卡尔算法的核心步骤)
    // 形式:[[A,B,12],[C,D,6],.....................]
    public Edge[] getEdge() {
        int index = 0; // 用于记录存放数组中边的索引
        Edge[] edges = new Edge[edgeNum]; // 动态初始化
        for (int i = 0; i < vertex.length; i++) { // 静态初始化
            for (int j = 0; j < vertex.length; j++) {
                // 取出邻接矩阵中可以直达的边
                if (Link_Array[i][j] != Max) {
                    // 将取出的边存放在数组中
                  edges[index++] = new Edge(vertex[i], vertex[j], Link_Array[i][j]);
                }
            }
        }
        return edges;
    }

    // 计算指定顶点对应的终点的索引(不太好理解),以后判断回路要用到
    public int getEnd(int[] vertex, int index) {
        while (vertex[index] != 0) {
            index = vertex[index];
        }
        return index;
    }

    // 克鲁斯卡尔算法
    public void KruskalAlgothm() {
        // 最小生成树数组元素的索引
        int index = 0;
        // 存放指定顶点对应的终点的索引
        int[] ends = new int[edgeNum];
        // 存放最小生成树的数组
        Edge[] result = new Edge[edgeNum];
        // 获取图中所有的边
        Edge[] edges = getEdge();
        // 对这些边进行排序
        SortEdge(edges);

        // 循环遍历图的边
        for (int i = 0; i < edgeNum; i++) {
            // 根据索引找到本次循环对应的边的一个顶点的索引
            int vertex_start = getVertex_Index(edges[i].start);
            // 根据索引找到本次循环对应的边的另一个顶点的索引
            int vertex_end = getVertex_Index(edges[i].end);
            // 获取开始顶点的终点的索引
            int m = getEnd(ends, vertex_start);
            // 获取另一顶点的终点的索引
            int n = getEnd(ends, vertex_end);

            // 判断,是否构成回路
            if (m != n) {
                // 没有构成回路,更新存放终点的数组
                ends[m] = n;
                // 将找到的边存放在结构数组中
                result[index++] = edges[i];
            }
        }

        // 输出结果数组
        System.out.println("最小生成树为:");
        for (int i = 0; i < index; i++) {
            System.out.println(result[i]);
        }
    }
}
2.边
package KruskalAlgothm;

public class Edge {
    // 成员变量
    char start; // 边的一个顶点
    char end; // 边的另一个顶点
    int value; // 边的权值

    // 构造方法
    public Edge() {
    }

    public Edge(char start, char end, int value) {
        this.start = start;
        this.end = end;
        this.value = value;
    }

    @Override
    public String toString() {
        return
                "<" + start + "," + end + ":" + value + '>';
    }
}
3.入口
package KruskalAlgothm;

import java.util.Arrays;

/**
 * @program: 18.克鲁斯卡尔算法
 * @description:
 * @author: Zhou Jian
 * @create: 2020-08-07 10:33
 */
public class Input {
    static int Max = Integer.MAX_VALUE; // 当两个顶点不能直达时,设置其权值为无穷大,这里使用int最大值表示

    public static void main(String[] args) {
        // 定义一个存放顶点的一维数组
        char[] vertex = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
        // 对应的邻接矩阵
        int[][] Link_Array = {
                {0, 12, Max, Max, Max, 16, 14},
                {12, 0, 10, Max, Max, 7, Max},
                {Max, 10, 0, 3, 5, 6, Max},
                {Max, Max, 3, 0, 4, Max, Max},
                {Max, Max, 5, 4, 0, 2, 8},
                {16, 7, 6, Max, 2, 0, 9},
                {14, Max, Max, Max, 8, 9, 0}
        };
        // 创建对象
        Kruskal kruskal = new Kruskal(vertex, Link_Array);
        // 打印邻接矩阵
        kruskal.print_LinkArray();

        // 打印获取到的边
        System.out.println("存放边的数组:");
        Edge[] edges = kruskal.getEdge();
        System.out.println("排序前:" + Arrays.toString(edges));

        kruskal.SortEdge(edges);
        System.out.println("排序后:" + Arrays.toString(edges));

        // 最小生成树
        kruskal.KruskalAlgothm();
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值