"Algorithm" notes 11-- minimum spanning tree

  • Minimum Spanning Tree applications
  • Segmentation Theorem
  • how are you
  • No weighting the data structure of FIG.
  • Prim's algorithm
  • Kruskal's algorithm

Minimum Spanning Tree applications

FIG weighted graph is a model of a weight value associated with each edge, which can represent many Fig applications, such as in an aeronautical charts, the edges represent these weights can represent the distance or cost; the circuit diagram of a , the edges, wires, weights or costs may represent the length of the wire. In these cases, the most interesting is how to minimize the cost. The minimum spanning tree is used to solve this problem without weighting in FIG. Minimum spanning tree algorithm associated with a wide range of applications in the communications, electronics, water, network, traffic lights industry.

FIG spanning tree is that it contains an acyclic connected subgraph of all its vertices, a weighted undirected graph of the minimum spanning tree (Minimum spanning tree) is one of its weight (weight of all the edges of the tree sum) minimum spanning tree.

Segmentation Theorem

FIG one kind of segmentation is that all vertices of a graph into two non-empty set of non-repeating. Cross edge is an edge connecting two vertices belonging to different sets.
And implicitly generally considered its complement to another set of vertices specified by specifying a slicing a set of vertices. Thus, a transverse side is connected to a vertex of the set and not in the other vertex in the set of edges.

Segmentation Theorem

SUMMARY segmentation theorem is: in a weighted graph, a given arbitrary segmentation, its transverse sides of the minimum of the minimum spanning tree weight must belong FIG.
Segmentation theorem is a theoretical minimum spanning tree algorithm.
To permit Mingqie points theorem, we need to know two important properties of the tree:

  • Generating a new ring of any two vertices are connected by an edge in the tree;
  • Deleting from the tree will get any edges are two separate trees.
    Next, by contradiction points Certificate Mingqie Theorem: Let e is a side cross minimum weight, minimum spanning tree T, assume T does not contain e, then e is added to T obtained necessarily contains a through e in FIG ring, and the ring there is at least another transverse edge - to f, f must be greater than the weight of e (e is because the weight is the weight of the weights of all edges and the minimum is not the same figure). Then deleting e f you can get a reservation weights smaller trees, which contradicts the assumption.

how are you

Segmentation theorem is the basis for all solve the problem minimum spanning tree algorithm, these algorithms are a special case of the greedy algorithm, greedy algorithm is a kind of selection at each step are taking the best or the best choice in the current state, thus leading to hope the result is the best or optimal algorithm. Solving the minimum spanning tree problem, use the segmentation Theorem to find a minimum spanning tree edge, repeated all the edges until you find the minimum spanning tree. The difference between these algorithms and determines that the stored segmentation smallest weight cross the edge.

The minimum spanning tree greedy algorithm : a weighted undirected graph, in the initial state of all sides are gray, to find a segmentation, it produces transverse edges are not black, the smallest weight that transverse edge marked in black, and so forth, until the V-1 labeled Article black side up.

Wherein V is the number of vertices in the graph, then Add these vertices are all connected, at least V-1 edges. The segmentation theorem, all edges are marked in black the minimum spanning tree, if the number is less than the black-side V-1, then there will not necessarily produce black edge segmentation, V-1 long enough to find a black side Article the minimum spanning tree is complete.

No weighting the data structure of FIG.

Weighted undirected graph data structure to not follow before undirected graph data structure, but redefined and Edge EdgeWeightedGraph classes are used to represent with weights edge and weighted undirected graph .

Achieved with weight of edge Edge

public class Edge implements Comparable<Edge> {
    private final int v; 
    private final int w; 
    private final double weight; 

    public Edge(int v, int w, double weight) {
        this.v = v;
        this.w = w;
        this.weight = weight;
    }

    public double weight() {
        return this.weight;
    }

    public int either() {
        return this.v;
    }

    public int other(int vertex) {
        if (v == vertex)
            return w;
        if (w == vertex)
            return v;
        else
            throw new RuntimeException("Inconsistent edge");
    }

    public int compareTo(Edge that) {
        if (this.weight() < that.weight())
            return -1;
        else if (this.weight() > that.weight())
            return 1;
        else
            return 0;
    }

    public String toString() {
        return String.format("%d-%d %.2f", v, w, weight);
    }
}

and other methods may return either two endpoints connected by edges, weight represents the edge weight.

Achieve a weighted undirected graph EdgeWeightedGraph

public class EdgeWeightedGraph {
    private static final String NEWLINE = System.getProperty("line.separator");
    private final int V; // vertex
    private int E; // edge
    private Bag<Edge>[] adj;

    public EdgeWeightedGraph(int V) {
        this.V = V;
        this.E = 0;
        adj = (Bag<Edge>[]) new Bag[V];
        for (int v = 0; v < V; v++) {
            adj[v] = new Bag<Edge>();
        }
    }

    public EdgeWeightedGraph(In in) {
        this(in.readInt());
        int E = in.readInt();
        for (int i = 0; i < E; i++) {
            int v = in.readInt();
            int w = in.readInt();
            double weight = in.readDouble();
            Edge e = new Edge(v, w, weight);
            addEdge(e);
        }
    }

    public int V() {
        return V;
    }

    public int E() {
        return E;
    }

    public void addEdge(Edge e) {
        int v = e.either(), w = e.other(v);
        adj[v].add(e);
        adj[w].add(e);
        E++;
    }

    public Iterable<Edge> adj(int v) {
        return adj[v];
    }

    public String toString() {
        StringBuilder s = new StringBuilder();
        s.append(V + " vertices, " + E + " edges " + NEWLINE);
        for (int v = 0; v < V; v++) {
            s.append(v + ": ");
            for (Edge w : adj[v]) {
                s.append(w + " | ");
            }
            s.append(NEWLINE);
        }
        return s.toString();
    }

    public Bag<Edge> edges() {
        Bag<Edge> b = new Bag<Edge>();
        for (int v = 0; v < V; v++) {
            for (Edge w : adj[v]) {
                b.add(w);
            }            
        }
        return b;
    }

EdgeWeightedGraph very similar with and without the drawing of Graph, except substitute an integer Graph Edge objects as nodes in the linked list. adj (int v) may be indexed according to the method corresponding to the vertex adjacency list, each edge will appear twice, if one side is connected to vertex v and w, then this edge will also be added to the corresponding collar v and w then the table.

Prim's algorithm

The first method of calculation of the minimum spanning tree to be called learning algorithm Prim, every part of it will be added to a growing tree an edge. This tree is only a start vertex, V-1 and adds it to the edges, each vertex always next to the tree are not connected to the apex of the tree and added with a minimum weight tree.

But how can efficiently find the smallest weight edge of it, use the priority queue will be able to achieve this, and to ensure a sufficiently high efficiency. Because're looking for is a minimum weight edge, so here will use the priority queue MinPQ find the smallest element.

Further, Prim algorithm also uses a boolean array marked by the vertex indices [], and a queue named mst, the former has been added to indicate to the vertex of the minimum spanning tree, is used to queue stored in the minimum spanning tree comprising the edges.

Whenever an edge is added to the tree, it is also added to the vertex of a tree. To maintain a set containing all the transverse edges, it is necessary to connect the edges of the vertex and all other vertices are not added to the tree in the priority queue, by Marked [] array may identify such edges. Note that, with the addition of transverse edges, before joining the edge, those who connect the new vertex added to the tree and the other side has all the vertices in the tree are ineffective, because such edges have not been cross trimming, and its two vertices in the tree, so that the edges will not be added to the queue mst.

Next, to visually observe algorithm tinyEWG.txt trajectory data, tinyEWG.txt reads as follows:

8
16
4 5 0.35
4 7 0.37
5 7 0.28
0 7 0.16
1 5 0.32
0 4 0.38
2 3 0.17
1 7 0.19
0 2 0.26
1 2 0.36
1 3 0.29
2 7 0.34
6 2 0.40
3 6 0.52
6 0 0.58
6 4 0.93

FIG it represents contains eight vertices, edges 16, double the value representing the end of the edge weight.

The figure is tinyEWG.txt algorithm when processing the trajectory, each one after FIG algorithm is a visited vertex (to be added to the tree, adjacent to the side of the list has been processed), priority queue, and the status of FIG. . Priority queue content is displayed on one side, next to the tree has a new vertex asterisk in order.

Minimum spanning tree algorithm process as follows:

  • 将顶点0添加到最小生成树之中,将它的邻接链表中的所有边添加到优先队列之中。
  • 将顶点7和边0-7添加到最小生成树之中,将顶点的邻接链表中的所有边添加到优先队列之中。
  • 将顶点1和边1-7添加到最小生成树之中,将顶点的邻接链表中的所有边添加到优先队列之中。
  • 将顶点2和边0-2添加到最小生成树之中,将边2-3和6-2添加到优先队列之中。边2-7和1-2失效。
  • 将顶点3和边2-3添加到最小生成树之中,将边3-6添加到优先队列之中。边1-3失效。
  • 将顶点5和边5-7添加到最小生成树之中,将边4-5添加到优先队列之中。边1-5失效。
  • 从优先队列中删除失效的边1-3、1-5和2-7。
  • 将顶点4和边4-5添加到最小生成树之中,将边6-4添加到优先队列之中。边4-7和0-4失效。
  • 从优先队列中删除失效的边1-2、4-7和0-4。
  • 将顶点6和边6-2添加到最小生成树之中,和顶点6相关联的其他边均失效。

算法的具体实现:

public class LazyPrimMST {
    private boolean[] marked;
    private Queue<Edge> mst;
    private MinPQ<Edge> pq;

    public LazyPrimMST(EdgeWeightedGraph G) {
        pq = new MinPQ<Edge>();
        marked = new boolean[G.V()];
        mst = new Queue<Edge>();
        visit(G, 0);
        while (!pq.isEmpty()) {
            Edge e = pq.delMin();
            int v = e.either(), w = e.other(v);
            if (marked[v] && marked[w])
                continue;

            mst.enqueue(e);
            if (!marked[v])
                visit(G, v);
            if (!marked[w])
                visit(G, w);
        }
    }

    public void visit(EdgeWeightedGraph G, int v) {
        marked[v] = true;
        for (Edge e : G.adj(v)) {
            if (!marked[e.other(v)]) {
                pq.insert(e);
            }
        }
    }

    public Iterable<Edge> edges() {
        return mst;
    }

    // cmd /c --% java algs4.four.LazyPrimMST ..\..\..\algs4-data\tinyEWG.txt
    public static void main(String[] args) {
        In in = new In(args[0]);
        EdgeWeightedGraph ewg = new EdgeWeightedGraph(in);
        LazyPrimMST lazyPrim = new LazyPrimMST(ewg);
        double weight=0;
        for (Edge e : lazyPrim.edges()) {
            weight += e.weight();
            StdOut.println(e);
        }
        StdOut.println(weight);
    }
}

visit()方法的作用是为树添加一个顶点,将它标记为“已访问”,并将与它关联的所有未失效的边加入优先队列中。在while循环中,会从优先队列取出一条边,如果它没有失效,就把它添加到树中,否则只是将其从优先队列删除。然后再根据添加到树中的边的顶点,更新优先队列中横切边的集合。

Kruskal算法

Prim算法是一条边一条边地来构造最小生成树,每一步都为一棵树添加一条边。接下来要学习的Kruskal算法处理问题的方式则是按照边的权重顺序,从小到大将边添加到最小生成树中,加入的边不会与已经加入的边构成环,直到树中含有V-1条边为止。从一片由V颗单结点的树构成的森林开始,不断将两棵树合并,直到只剩下一颗树,它就是最小生成树。

同样是处理tinyEWG.txt,Kruskal算法的轨迹如下图:
【】

该算法首先会将所有的边加入到优先队列并按权重顺序排列,然后依次从优先队列拿到最小的边加入到最小生成树中,然后轮到处理1-3、1-5、2-7这三条边时,发现它们会使最小生成树形成环,说明这些顶点已经被包含到了最小生成树中,属于失效的边;接着继续处理4-5,随后1-2、4-7、0-4又被丢弃,把6-2加入树中后,最小生成树已经有了V-1条边,最小生成树已经形成,查找结束。

算法的具体实现为:

public class KruskalMST {
    private Queue<Edge> mst;
    private double _weight = 0;

    public KruskalMST(EdgeWeightedGraph G) {
        mst = new Queue<Edge>();
        MinPQ<Edge> pq = new MinPQ<Edge>();
        UF uf = new UF(G.V());

        for (Edge e : G.edges()) {
            pq.insert(e);
        }

        while (!pq.isEmpty() && mst.size() < G.V() - 1) {
            Edge e = pq.delMin();
            int v = e.either(), w = e.other(v);
            if (uf.connected(v, w))
                continue;
            uf.union(v, w);
            mst.enqueue(e);
            _weight += e.weight();
        }
    }

    public Iterable<Edge> edges() {
        return mst;
    }

    public double weight() {
        return _weight;
    }

    // cmd /c --% java algs4.four.KruskalMST ..\..\..\algs4-data\tinyEWG.txt
    public static void main(String[] args) {
        In in = new In(args[0]);
        EdgeWeightedGraph ewg = new EdgeWeightedGraph(in);
        KruskalMST kruskalMST = new KruskalMST(ewg);
        for (Edge e : kruskalMST.edges()) {
            StdOut.println(e);
        }
        StdOut.println(kruskalMST.weight());
    }
}

这里同样使用了MinPQ来为边排序,并使用了之前Union-Find算法中实现的的Quick Union数据结构,用它可以方便地识别会形成环的边,最终生成的最小生成树同样保存在名为mst的队列中。

Guess you like

Origin www.cnblogs.com/zhixin9001/p/12129209.html