Java使用Prim算法和Kruskal算法实现最小生成树

Prim算法:

算法思路:

1.定义一个临时的一维数组,用于存放可用的连接边,数组下标为顶点序号,值为权值
2.任选一个点作为起点,以起点的所有权值对数组进行初始化
3.找出数组中最小权值的边,即为最小生成树中的一条有效边
4.将找到的最小边在数组中赋值为0,代表已经使用过。并将数组与找到顶点的所有边进行比较,若顶点的边的权值比当前数组存放的可用边的权值小,则进行覆盖
5.重复循环2,3,4的操作直至遍历完所有顶点

/**
     * prim算法实现最小生成树
     * @param arr 图的邻接矩阵
     * @param size  图的节点个数
     * @param nodes 存放节点名称的数组
     */
    private static void Prim(int[][] arr,int size,char[] nodes){
        //创建一个一维数组,存放用于比较最小权值的顶点权值,值为0表示该点已经比较过
        int[] lowcost = new int[size];

        //初始化为原数组第一个顶点的权值
        lowcost = Arrays.copyOfRange(arr[0],0,size);

        //初始化权值之和为0
        int sum = 0;

        //循环比较
        for (int i = 0; i < size-1; i++) {
            int min = -1;
            //找到最小权值节点
            for (int j = 0; j < size; j++) {
                if(lowcost[j] != 0 && lowcost[j] < Integer.MAX_VALUE){
                    if(min == -1 || lowcost[j] < lowcost[min] ){
                        min = j;
                    }
                }
            }
            //如果所有节点都比较过(值为0),则直接退出
            if(min == -1) break;

            //输出加入的新节点
            System.out.println("加入新节点:"+nodes[min]+"   权值为:"+lowcost[min]);

            //增加权值之和
            sum += lowcost[min];
            
            // 将当前节点的值修改成0
            lowcost[min] = 0;

            //将存放最小权值的数组与下一个节点的所有连接点对比,找出最小权值
            for (int j = 0; j < size; j++) {
                if(arr[min][j] < lowcost[j] ){
                    lowcost[j] = arr[min][j];
                }
            }
        }
        System.out.println("权值之和:"+sum);
    }

Kruskal算法:

算法思路:

1.现将所有边进行权值的从小到大排序
2.定义一个一维数组代表连接过的边,数组的下标为边的起点,值为边的终点
3.按照排好序的集合用边对顶点进行依次连接,连接的边则存放到一维数组中
4.用一维数组判断是否对已经连接的边能构成回路,有回路则无效,没回路则是一条有效边
5.重复3,4直至遍历完所有的边为止,即找到最小生成树

/**
     * Kruskal算法
     * @param array 各边权重数组
     * @param size  节点个数
     * @param chars 存放节点名称的数组
     */
    private static void Kruskal(int[][] array,int size,char[] chars){
        //创建一维数组,数组下标为连线的起点,下标对应的值为连线的终点
        int[] parent = new int[size];

        for (int i = 0; i < size; i++) {
            parent[i] = 0;
        }

        //定义初始权值之和为0
        int sum = 0;
        for (int i = 0; i < array.length; i++) {
            //找到起始节点和终点在连接集和中的最后一个节点
            int start = find(parent,array[i][0]);
            int end = find(parent,array[i][1]);

            //若通过起点和终点找到的最终连接点不是同一个点,则不是回环
            if(start != end){
                parent[start] = end;
                System.out.println("起点:"+chars[array[i][0]]+"   终点:"+chars[array[i][1]]+"   权重:"+array[i][2]);
                sum += array[i][2];
            }
        }
        System.out.println("权值之和:"+sum);
    }

    //获取集和的最后一个节点
    private static int find(int[] parent, int index) {
        while(parent[index] > 0){
            index = parent[index];
        }
        return index;
    }

在这里插入图片描述

分别用两种算法实现上图最小生成树代码:

public static void main(String[] args) {
        //初始化权值矩阵
        int[][] arr = new int[][]{
                {0,2,Integer.MAX_VALUE,5,Integer.MAX_VALUE,8,Integer.MAX_VALUE},
                {2,0,7,7,2,Integer.MAX_VALUE,Integer.MAX_VALUE},
                {Integer.MAX_VALUE,7,0,Integer.MAX_VALUE,3,Integer.MAX_VALUE,Integer.MAX_VALUE},
                {5,7,Integer.MAX_VALUE,0,6,7,3},
                {Integer.MAX_VALUE,2,3,6,0,Integer.MAX_VALUE,4},
                {8,Integer.MAX_VALUE,Integer.MAX_VALUE,7,Integer.MAX_VALUE,0,4},
                {Integer.MAX_VALUE,Integer.MAX_VALUE,Integer.MAX_VALUE,3,4,4,0}
        };
        char[] chars = new char[]{'A','B','C','D','E','F','G'};
        System.out.println("Prim算法:");
        Prim(arr,chars.length,chars);

        //换行
        System.out.println();

        int[][] array = new int[][]{
                {0,1,2},
                {1,4,2},
                {2,4,3},
                {3,6,3},
                {4,6,4},
                {5,6,4},
                {0,3,5},
                {3,4,6},
                {1,2,7},
                {1,3,7},
                {3,5,7},
                {0,5,8},
        };
        System.out.println("Kruskal算法:");
        Kruskal(array,chars.length,chars);
    }

结果:

在这里插入图片描述

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值