常用十大算法_普里姆(prim)算法,克鲁斯卡尔(Kruskal)算法

求最小生成树MST:Prim算法(普里姆算法)

最小生成树简称为MST,给定一个带权的无向连通图,如何选取一棵生成树,使树上所有边上权的总和为最小,这叫最小生成树。

常用十大算法_普里姆(prim)算法,克鲁斯卡尔(Kruskal)算法_第1张图片

上图中红框标记的子图就是我们要的最小生成树

引入MST概念后,我们以经典的修路问题来引出prim算法

【例子】如下图,有一个7村庄(A~G),需要修路将7个村庄连通,且不同路的路径不同(权值不同),要求既要连通7村,也要路径最短

常用十大算法_普里姆(prim)算法,克鲁斯卡尔(Kruskal)算法_第2张图片

算法分析:

就是一个求MST的题,接下来我们用prim算法求MST

prim算法核心就是:指定一个起点顶点,标记该顶点为已访问,将该顶点可能直连的顶点(未访问的)找到。然后根据连接顶点路径长度,找到最短路径即可。在重复顶点个数的次数后,停止循环。就能得到MST树。

prim算法的操作有点类似贪心算法。局部最优得到全局最优。

代码实现:(代码中包含图结构的知识,不清楚的朋友请猛击此处(待完善!!!)查看我前面的文章)

package cn.dataStructureAndAlgorithm.demo.tenAlgorithm.prim;
class Graph{
    int vertexes;//顶点数
    char[] verData;//顶点数据
    int[][] edges;//邻接矩阵

    public Graph(int vertexes) {
        this.vertexes = vertexes;
        this.verData=new char[vertexes];
        this.edges=new int[vertexes][vertexes];
    }
}
class MinTree{
    public void createGraph(Graph graph,char[] verData,int[][] edges){
        int i,j;
        for (i=0;i: "+graph.edges[index1][index2]);
            minWeight=10000;//重置
            visited[index2]=1;//终点顶点已被访问
        }
    }
}
public class 普里姆算法_prim_修路问题 {
    public static void main(String[] args) {
        char[] verData={'A','B','C','D','E','F','G'};
        int vertexes=verData.length;
        int[][] edges=new int[][]{
                {10000,5,7,10000,10000,10000,2},
                {5,10000,10000,9,10000,10000,3},
                {7,10000,10000,10000,8,10000,10000},
                {10000,9,10000,10000,10000,4,10000},
                {10000,10000,8,10000,10000,5,4},
                {10000,10000,10000,4,5,10000,6},
                {2,3,10000,10000,4,6,10000}
        };
        Graph graph=new Graph(vertexes);
        MinTree minTree=new MinTree();
        minTree.createGraph(graph,verData,edges);
        minTree.prim(graph,0);
    }
}
<顶点A--顶点G>: 2
<顶点G--顶点B>: 3
<顶点G--顶点E>: 4
<顶点E--顶点F>: 5
<顶点F--顶点D>: 4
<顶点A--顶点C>: 7

 

 

求最小生成树MST:Kruskal算法(克鲁斯卡尔算法)

和prim算法对应的就是K算法,他们都是求带权最小生成树的算法。

【例子】七个公交站点(A~G),需要将七个站点连通,每个路的长度(权)不同,如何修路使站点连通,且长度最短

常用十大算法_普里姆(prim)算法,克鲁斯卡尔(Kruskal)算法_第3张图片

算法分析:

就是一个求MST的题,接下来我们用K算法求MST

K算法的核心是:将各个边按权值大小排序,将排序的边按顺序选取,同时要满足所选取的边不能与之前选取的边形成回路。若不满足,就跳过该边(如下图第4步)。

常用十大算法_普里姆(prim)算法,克鲁斯卡尔(Kruskal)算法_第4张图片

 所以,K算法的核心问题集中在两点上:

1)将边按权值排序

2)将边添加到最小生成树时,如何判断是否形成回路

对于1)而言,可以从八大排序算法中,任选一种来作排序,也可以利用Java特性,继承Comparable接口,通过实现compareTo方法来实现排序

对于2)而言,采用终点相同判定来实现。即每个边的顶点都对应一个终点(与之连通的最大顶点),当终点相同时说明产生回路。如下图,C终点为F,F终点为F,故权值为6的边,不能连入,否则将形成回路

常用十大算法_普里姆(prim)算法,克鲁斯卡尔(Kruskal)算法_第5张图片

 代码实现:(其中的getEnd方法使用了并查集原理)

package cn.dataStructureAndAlgorithm.demo.tenAlgorithm.kruskal;

import java.util.Arrays;

class Graph{
    int vertexes;//顶点数
    char[] verData;//顶点数据
    int[][] edges;//邻接矩阵
    //Edata类是对边的具体描述类,该类继承了Comparable接口
    static class EData implements Comparable{
        char start;//记录边的一个顶点
        char end;//记录边的另一个顶点
        int weight;//边的权值

        public EData(char start, char end, int weight) {
            this.start = start;
            this.end = end;
            this.weight = weight;
        }

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

        @Override
        public String toString() {
            return "EData{<" + start +","+ end +","+ weight +">}";
        }
    }
    public Graph(int vertexes) {
        this.vertexes = vertexes;
        this.verData=new char[vertexes];
        this.edges=new int[vertexes][vertexes];
    }
}
class MinTree{
    private int valueEdges=0;
    private Graph graph;
    private int INF;
    public MinTree(Graph graph,char[] verData,int[][] edges,int INF) {
        //制图
        for (int i=0;i

普里姆与克鲁斯卡尔算法: 

> 普利姆算法时间复杂度为O(n2),该算法适用于求边稠密网的最小支撑树
> 克鲁斯卡尔算法的时间复杂度为O(eloge),适用于求稀疏网的最小支撑树
> 克鲁斯卡尔算法在执行过程中,以边为核心,而普利姆算法则是以顶点为核心,在算法执行过程中,则是把顶点集合分为已经访问的顶点集合和未访问的顶点集合,通过不断的寻找两个集合间的最短边实现的。 

 


其他常用算法,见下各链接

【常用十大算法_二分查找算法】

【常用十大算法_分治算法】

【常用十大算法_贪心算法】

【常用十大算法_动态规划算法(DP)】

【常用十大算法_KMP算法】

【常用十大算法_迪杰斯特拉(Dijkstra)算法,弗洛伊德(Floyd)算法】

【常用十大算法_回溯算法】

 

【数据结构与算法整理总结目录 :>】<-- 宝藏在此(doge)  

 

你可能感兴趣的:(数据结构与算法)