最小生成树:Prim算法、Kruskal算法和Boruvka算法

最小生成树:最小权重生成树的简称。在一给定的加权无向图G=(V,E)中,(u,v)代表连接顶点u和顶点v的便,而w(u,v)代表此边的权重。

若存在T中的顶点是所有V,T的边是E的子集中,且T中没有环,而w(T)最小,则此T为G的最小生成树。

最小生成树:Prim算法、Kruskal算法和Boruvka算法_第1张图片

Prim算法

普里姆算法(Prim’s algorithm),图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点,且其所有边的权值之和亦为最小。

算法原理

“加点法”, 每次迭代选择代价最小的边对应的点,加入到最小生成树中。算法从某一个顶点s开始,逐渐长大覆盖整个连通网的所有顶点。

Step 01:以某一个点开始,寻找当前该点可以访问的所有的边;

Step 02:在寻找的边中寻找最小的边,这个边必须由一个点还没有访问过, 将还没有访问的点加入我们的集合,记录添加的边;

Step 03:寻找当前集合可以访问的所有边,重复Step 02,直到没有新的点可以加入;

Step 04: 此时由所有边构成的树即为最小生成树。

代码

package Graph;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Prim {
    public static List vertexList = new ArrayList();//结点集
    public static List EdgeQueue = new ArrayList();//边集
    public static List newVertex = new ArrayList();//已经 访问过的结点

    public static void main(String[] args) {
        primTree();
    }

    public static void buildGraph() {
        Vertex v1 = new Vertex("a");
        Prim.vertexList.add(v1);
        Vertex v2 = new Vertex("b");
        Prim.vertexList.add(v2);
        Vertex v3 = new Vertex("c");
        Prim.vertexList.add(v3);
        Vertex v4 = new Vertex("d");
        Prim.vertexList.add(v4);
        Vertex v5 = new Vertex("e");
        Prim.vertexList.add(v5);
        addEdge(v1, v2, 6);
        addEdge(v1, v3, 7);
        addEdge(v2, v3, 8);
        addEdge(v2, v5, 4);
        addEdge(v2, v4, 5);
        addEdge(v3, v4, 3);
        addEdge(v3, v5, 9);
        addEdge(v5, v4, 7);
        addEdge(v5, v1, 2);
        addEdge(v4, v2, 2);
    }

    public static void addEdge(Vertex a, Vertex b, int w) {
        Edge e = new Edge(a, b, w);
        Prim.EdgeQueue.add(e);
    }

    public static void primTree() {
        buildGraph();
        Vertex start = vertexList.get(0);
        newVertex.add(start);
        for (int n = 0; n < vertexList.size() - 1; n++) {
            Vertex temp = new Vertex(start.key);
            Edge tempedge = new Edge(start, start, 1000);
            for (Vertex v : newVertex) {
                for (Edge e : EdgeQueue) {
                    if (e.start == v && !containVertex(e.end)) {
                        if (e.key < tempedge.key) {
                            temp = e.end;
                            tempedge = e;
                        }
                    }
                }
            }
            newVertex.add(temp);
        }
        Iterator it = newVertex.iterator();
        while (it.hasNext()) {
            Vertex v = (Vertex) it.next();
            System.out.println(v.key);
        }
    }

    private static boolean containVertex(Vertex vte) {
        for (Vertex v : newVertex) {
            if (v.key.equals(vte.key))
                return true;
        }
        return false;
    }
    

    //结点结构
    private static class Vertex {
        String key;
        Vertex(String key){
            this.key = key;
        }
    }

    //边结构
    private static class Edge {
        Vertex start;
        Vertex end;
        int key;

        public Edge(Vertex start, Vertex end, int key) {
            this.start = start;
            this.end = end;
            this.key = key;
        }
    }
}

Kruskal算法

克鲁斯克尔算法(Kruskal)是一种查找最小生成树的算法,由Joseph Kruskal在1956年发表。解决同类问题的还有Prim算法和Boruvka算法,都是贪心算法的应用。

按照边的权重顺序(从小到大)将边加入生成树中,但是若加入该边会与生成树形成环则不加入该边。直到树中含有V-1条边为止。这些边组成的就是该图的最小生成树。

算法原理

“加边法”,初始化最小生成树边数为0,每迭代一次就选择一条满足条件的最小边为代价,加入到最小生成树的边集合里。

Step 01:把图中最所有边按代价从小到大排序;

Step 02:把图中的n个顶点堪称独立的n棵树组成的森林;

Step 03:按权值从小到大选择边,所选的边连接的两个顶点u和v,应该属于两颗不同的树,则成为最小生成树的一条边,并将两棵树合并为一棵树。

Step 04:重复Step 03,直到所有顶点都在一棵树内或者有n-1条边为止。

Boruvka 算法的演示如下(引自维基zh.wikipedia.org):
最小生成树:Prim算法、Kruskal算法和Boruvka算法_第2张图片

Boruvka算法

Brouvka算法又名Sollin算法。是最小生成树最古老的一个算法之一,其实是Prim算法和Kruskal算法的综合,每次迭代同时扩展多课子树,直到得到最小生成树T。适用于并行处理一个图。

所有当前的连通块向其他连通块扩展出最小边,直到只剩一个连通块”,其中取最小边的贪心思想是 Kruskal 的主体,而向外扩展又是 Prim 的思想 —— 基于另外两种生成树算法,Boruvka 的正确性显然。

复杂度:最坏O((n+m)logn)O((n+m)logn),随机图O(n+m)O(n+m)。

Boruvka 算法的演示如下(引自维基 zh.wikipedia.org):
最小生成树:Prim算法、Kruskal算法和Boruvka算法_第3张图片)]

你可能感兴趣的:(学习笔记)