算法-最小生成树算法(普里姆算法 Prim`s algorithm)

92 篇文章 0 订阅
12 篇文章 0 订阅

Prim`s algorithm

概述

  • 普里姆算法(Prim`s algorithm)是求出最小生成树的算法, 也就是在包含 n个顶点的带权无向连通图中, 找出(n-1)条边的最小耗费生成树(Minimum Cost Spanning Tree), 简称 MST
  • 普里姆算法的时间复杂度为: 邻接矩阵 O(v^2), 邻接表 O(elog2v) e为网中的边数

修路问题

  • 有叫(A,B,C,D,E,F,G)的7个村庄, 现在需要将这7个村庄通过修路连通. 各个村庄的距离用边线权值来表示, 比如 A-B距离5公里
  • 需要保证各个村庄都能连通, 且修建公路的总里程为最短

在这里插入图片描述

  • 求出最小生成树的步骤:
  1. 从顶点开始处理, 其中选出公里数最近的, 也就是 A-G(权值2): <A,G>
    A-C(权值7), A-G(权值2), A-B(权值5)
  2. <A,G>开始, 将与 A和 G顶点相邻的, 且还未访问的顶点进行处理: <A,G,B>
    A-C(权值7), A-B(权值5), G-B(权值3), G-E(权值4), G-F(权值6)
  3. <A,G,B>开始, 将与 A,G,B顶点相邻的, 且还未访问的顶点进行处理: <A,G,B,E>
    A-C(权值7), G-E(权值4), G-F(权值6), B-D(权值9)
  4. 处理 F <A,G,B,E,F>, 对应的边是 E-F(权值5)
  5. 处理 D <A,G,B,E,F,D>, 对应的边是 F-D(权值4)
  6. 处理 C <A,G,B,E,F,D,C>, 对应的边是 A-C(权值7)
  • 代码实现

public class PrimAlgorithmApp {
    public static void main(String[] args) {
        /** 定义顶点(村庄)*/
        char[] data = new char[] {'A','B','C','D','E','F','G'};
        /** 设置邻接矩阵的顶点与顶点间的边(附带权值), 权值9999表示不连通*/
        int[][] matrix = new int[][] {
                {9999,5,7,9999,9999,9999,2},
                {5,9999,9999,9,9999,9999,3},
                {7,9999,9999,9999,8,9999,9999},
                {9999,9,9999,9999,9999,4,9999},
                {9999,9999,8,9999,9999,5,4},
                {9999,9999,9999,4,5,9999,6},
                {2,3,9999,9999,4,6,9999},};
        /** 创建图实例*/
        MSTGraph graph = new MSTGraph(data.length);
        /** 创建最小生成树类实例*/
        MinimumCostSpanningTree mst = new MinimumCostSpanningTree();
        /** 创建邻接矩阵*/
        mst.createGraph(graph, data, matrix);
        /** 打印邻接矩阵*/
        mst.showGraph(graph);
        /** 求出最小生成树*/
        mst.prim(graph, 1);
    }
}

/** 定义最小生成树图类*/
class MSTGraph {
    /** 顶点个数*/
    int vertexCount;
    /** 顶点数据*/
    char[] vertexes;
    /** 邻接矩阵*/
    int[][] matrix;

    public MSTGraph(int count) {
        this.vertexCount = count;
        vertexes = new char[count];
        matrix = new int[count][count];
    }
}

/** 定义创建最小生成树的类*/
class MinimumCostSpanningTree {
    /** 创建邻接矩阵
     * @param graph 图对象
     * @param data 图的各个顶点的值
     * @param matrix 图的邻接矩阵*/
    public void createGraph(MSTGraph graph, char data[], int[][] matrix) {
        int i, j;
        for(i = 0; i < data.length; i++) {
            graph.vertexes[i] = data[i];
            for(j = 0; j < data.length; j++) {
                graph.matrix[i][j] = matrix[i][j];
            }
        }
    }

    /** 打印邻接矩阵*/
    public void showGraph(MSTGraph graph) {
        for(int[] link: graph.matrix) {
            System.out.println(Arrays.toString(link));
        }
    }

    /** 求出最小生成树
     * @param graph 图
     * @param v 生成时, 起始顶点 'A'->0 'B'->1...*/
    public void prim(MSTGraph graph, int v) {
        /** 标记已被访问过的顶点, 按序每个顶点默认标记为0, 表示未访问过*/
        int visited[] = new int[graph.vertexCount];
        /** 将当前顶点标记为已访问*/
        visited[v] = 1;
        /** 临时存储已访问顶点下标*/
        int h1 = -1;
        /** 临时存储未访问顶点下标*/
        int h2 = -1;
        /** 初始权值设为9999表示不连通*/
        int minWeight = 9999;
        /** 最小生成树的最终边个数为 graph.vertexCount-1个*/
        for(int k = 1; k < graph.vertexCount; k++) {
            for(int i = 0; i < graph.vertexCount; i++) { /** i表示已被访问过的顶点*/
                for(int j = 0; j< graph.vertexCount;j++) { /** i表示未访问过的顶点*/
                    /** 已访问的顶点 && 未访问的顶点 && 公里(权值)可达*/
                    if(visited[i] == 1 && visited[j] == 0 && graph.matrix[i][j] < minWeight) {
                        minWeight = graph.matrix[i][j];
                        h1 = i;
                        h2 = j;
                    }
                }
            }
            /** 找到一条边是最小的可达边*/
            System.out.println("边<" + graph.vertexes[h1] + "," + graph.vertexes[h2] + "> 权值: " + minWeight);
            /** 将当前节点标记为已经访问*/
            visited[h2] = 1;
            /** 重新将 minWeight设为不连通*/
            minWeight = 9999;
        }
    }

}

输出:
[9999, 5, 7, 9999, 9999, 9999, 2]
[5, 9999, 9999, 9, 9999, 9999, 3]
[7, 9999, 9999, 9999, 8, 9999, 9999]
[9999, 9, 9999, 9999, 9999, 4, 9999]
[9999, 9999, 8, 9999, 9999, 5, 4]
[9999, 9999, 9999, 4, 5, 9999, 6]
[2, 3, 9999, 9999, 4, 6, 9999]
边<B,G> 权值: 3
边<G,A> 权值: 2
边<G,E> 权值: 4
边<E,F> 权值: 5
边<F,D> 权值: 4
边<A,C> 权值: 7

如果您觉得有帮助,欢迎点赞哦 ~ 谢谢!!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值