最小生成树

参考:勿在浮沙筑高台http://blog.csdn.net/luoshixian099/article/details/51908175

最小生成树

图的最小生成树是不重复的连接所有顶点所花的最低成本
在这里插入图片描述
如上图中图,最小生成树为粗黑线的边集合

Prim算法

思想:
{V}为已生成树的集合,lowcost保存每个顶点与已生成树集合中的所有顶点中最低的成本,adjvex保存每个顶点与{V}集合中最低成本关联的顶点,每次从lowcost中找到最低成本,在adjvex找到对应的关联的顶点加到集合{V}中,然后重置lowcost中的每个顶点的最低成本(与新加入的顶点的成本对比)

实现:

import java.util.Arrays;

// 图的最小生成树算法
public class MiniSpanTree {
    private static int maxv = Integer.MAX_VALUE;
    private static String[]  vexs = new String[]{"v0","v1","v2","v3","v4","v5","v6","v7","v8"};
    private static int vlen = vexs.length;

    // 普利姆算法
    // {param} arc 邻接矩阵
    public static void prim(int[][] adjMatrix){
       int[] lowcost = new int[vlen];
       int[] adjvex = new int[vlen];

       // 假设从顶点0开始查找,则最开始只有顶点0
       // 所有顶点的关联顶点都是顶点0
       for (int i=0;i<vlen;i++){
           lowcost[i] = adjMatrix[0][i];
           adjvex[i] = 0;
       }

       // 找到n-1条边即可
       for (int i=1;i<vlen;i++){


           int min = maxv;// 查找最小成本
           int minv = 0;// 最小成本的相关顶点
           for (int j=0;j<lowcost.length;j++){
               // 如果最小成本为0,则认为已经在生成树中
               if (lowcost[j]!=0&&lowcost[j]<min){
                   min = lowcost[j];
                   minv = j;// 相关顶点
               }
           }

           System.out.printf("连接:%s----%s\n",vexs[minv],vexs[adjvex[minv]]);
           lowcost[minv] = 0;// 置为0,已经查找完毕

           // 重新计算lowcost,因为生成树集合有新加顶点minv
           for (int k=0;k<vlen;k++){
               if (lowcost[k]!=0&&adjMatrix[minv][k]< lowcost[k]){
                   lowcost[k] = adjMatrix[minv][k];
                   adjvex[k] = minv;
               }
           }
       }
    }


    public static void main(String[] args){
        int[][] adjMatrix = new int[][]{
                {0,10,maxv,maxv,maxv,11,maxv,maxv,maxv},
                {10,0,18,maxv,maxv,maxv,16,maxv,12},
                {maxv,maxv,0,22,maxv,maxv,maxv,maxv,8},
                {maxv,maxv,22,0,20,maxv,maxv,16,21},
                {maxv,maxv,maxv,20,0,26,maxv,7,maxv},
                {11,maxv,maxv,maxv,26,0,17,maxv,maxv},
                {maxv,16,maxv,maxv,maxv,17,0,19,maxv},
                {maxv,maxv,maxv,16,7,maxv,19,0,maxv},
                {maxv,12,8,21,maxv,maxv,maxv,maxv,0}
        };


      
        System.out.println("prim alg");
        prim(adjMatrix);
    }

}

Karuskal算法

思想:
prim算法采用一步步查找与生成树中的最低成本的顶点,karuskal算法则采用查找最低成本边的思想。输入元素为边集数组,先对边集数组按照权重从小到达排序,则遍历边集数组,如果新遍历的边只要有一个顶点不在最小生成树中(防止形成环)则合并新查找到的边与之前的生成树

tree数组保存生成树信息
example:tree = [1,2,0,0,0]
则顶点0—1----2 当前为一棵树,如果多棵树的结尾元素不一致则可以认为他们不是一棵树,则进行合并

实现:

import java.util.Arrays;

// 图的最小生成树算法
public class MiniSpanTree {
    private static int maxv = Integer.MAX_VALUE;
    private static String[]  vexs = new String[]{"v0","v1","v2","v3","v4","v5","v6","v7","v8"};
    private static int vlen = vexs.length;

    // kruskal算法使用边集
    public static class Edge implements Comparable<Edge>{
        int begin;
        int end;
        int weight;// 权重

        public Edge(int begin,int end,int weight){
            this.begin = begin;
            this.end = end;
            this.weight = weight;
        }

        @Override
        public int compareTo(Edge o) {
            return this.weight - o.weight;
        }
    }

    // 卡鲁斯卡尔算法
    // {param} edges:边集数组
    // {param} vexNum:顶点数
    public static void kruskal(Edge[] edges){
        int[] tree = new int[vlen];// 生成树数组
        // 初始化
        for (int i=0;i<tree.length;i++)
            tree[i] = 0;

        // 边集边集数组
        for (int i=0;i<edges.length;i++){
            int begin = edges[i].begin;
            int end = edges[i].end;

            // 查找边的两个顶点在各自树中的结尾顶点
            // 如果不一致则可以认为两个顶点不在一颗
            // 树中,可以合并
            int n = findTree(tree,begin);
            int m = findTree(tree,end);
            if (n!=m){
                tree[n] = m;// 串联起来
                System.out.printf("连接:%s----%s\n",vexs[begin],vexs[end]);
            }
        }
    }

    // 查找树的结尾结点
    private static int  findTree(int[] tree,int f){
        while (tree[f]>0)
            f = tree[f];
        return f;
    }



    public static void main(String[] args){

        Edge[] edges = new Edge[]{
                new Edge(4,7,7),
                new Edge(2,8,8),
                new Edge(0,1,10),
                new Edge(0,5,11),
                new Edge(1,8,12),
                new Edge(3,7,16),
                new Edge(1,6,16),
                new Edge(5,6,17),
                new Edge(1,2,18),
                new Edge(6,7,19),
                new Edge(3,4,20),
                new Edge(3,8,21),
                new Edge(2,3,22),
                new Edge(3,6,24),
                new Edge(4,5,26),
        };

        System.out.println("kruskal alg");
        kruskal(edges);
    }

}

总结

prim算法从顶点出发,karuskal算法从边进行考虑,当顶点更多时适合使用karuskal算法,当边更多时使用prim算法更合适

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值