数据结构与算法分析(Java语言描述)(31)—— 使用 Prim 算法求有权图的最小生成树(MST)

来源:互联网 发布:香港网络歌手小背心 编辑:程序博客网 时间:2024/05/20 16:10

最小生成树

这里写图片描述

这里写图片描述


切分定理


这里写图片描述

这里写图片描述


LazyPrim

这里写图片描述

package com.dataStructure.weight_graph;import com.dataStructure.heap.MinHeap;import java.util.ArrayList;import java.util.List;public class LazyPrimMST{    private WeightedGraph graph;    // 存放输入的图    private boolean[] visited;  // 图中节点的访问状态    private List<Edge> mst; // 最小生成树经过的边    private Number mstWeight;   // 最小生成树的权重    private MinHeap<Edge> minHeap;  // 用于缓存 edge 的最小堆    // 构造函数,初始化私有字段    public LazyPrimMST(WeightedGraph graph){        this.graph = graph;        visited = new boolean[graph.V()];        mst = new ArrayList<>();        mstWeight = 0;        minHeap = new MinHeap<>(graph.E()); // 最小堆的大小等于边数        visit(0);   // 从节点 0 开始访问图        while (!minHeap.isEmpty()){ // 当最小堆非空            Edge edge = minHeap.extractMin();   // 获取最小边            if (visited[edge.getV()] == visited[edge.getW()])   // 如果最小边的两个端点都被访问                continue;   // 跳出本次循环            mst.add(edge);  // 将最小边放入 mst 中            if (!visited[edge.getV()])  // 访问最小边两端点中未被访问的端点                visit(edge.getV());            else                visit(edge.getW());        }        for (Edge edge:mst) // 计算最小生成树的权重            mstWeight = mstWeight.doubleValue() + edge.getWeight().doubleValue();    }    public void visit(int i){   // 访问节点 i        visited[i] = true;        for (Edge edge:graph.adjacentNode(i))   // 将 i 的邻接节点(未被访问的)与 i 之间的边加入最小堆中            if (!visited[edge.getAnotherNode(i)])                minHeap.insert(edge);    }    public Number getMstWeight(){   // 返回最小生成树的权重        return mstWeight;    }    public List<Edge> getMst() {    // 返回最小生成树        return mst;    }}//public class LazyPrimMST {//    private WeightedGraph G;    // 图的引用//    private MinHeap<Edge> pq;   // 最小堆, 算法辅助数据结构//    private boolean[] visited;           // 标记数组, 在算法运行过程中标记节点i是否被访问//    private List<Edge> mst;   // 最小生成树所包含的所有边//    private Number mstWeight;           // 最小生成树的权值////    // 构造函数, 使用Prim算法求图的最小生成树//    public LazyPrimMST(WeightedGraph graph) {////        // 算法初始化//        G = graph;//        pq = new MinHeap<>(G.E());  // 堆的大小等于 g 的边数//        visited = new boolean[G.V()];   // 节点的访问状态//        mst = new ArrayList<>();////        // Lazy Prim//        visit(0);//        while (!pq.isEmpty()) {//            // 使用最小堆找出已经访问的边中权值最小的边//            Edge e = pq.extractMin();//            // 如果这条边的两端都已经访问过了, 则扔掉这条边//            if (visited[e.getV()] == visited[e.getW()])//                continue;//            // 否则, 这条边则应该存在在最小生成树中//            mst.add(e);////            // 访问和这条边连接的还没有被访问过的节点//            if (!visited[e.getV()])//                visit(e.getV());//            else//                visit(e.getW());//        }////        // 计算最小生成树的权值//////        mstWeight = mst.get(0).getWeight();////        for (int i = 1; i < mst.size(); i++)////            mstWeight = mstWeight.doubleValue() + mst.get(i).getWeight().doubleValue();////        mstWeight = 0;//        for (Edge edge:mst)//            mstWeight = mstWeight.doubleValue() + edge.getWeight().doubleValue();////    }////    // 访问节点v//    private void visit(int v) {////        assert !visited[v];//        visited[v] = true;////        // 将和节点v相连接的所有未访问的边放入最小堆中//        for (Edge e : G.adjacentNode(v))//            if (!visited[e.getAnotherNode(v)])//                pq.insert(e);//    }////    // 返回最小生成树的所有边//    List<Edge> mstEdges() {//        return mst;//    }////    ;////    // 返回最小生成树的权值//    Number result() {//        return mstWeight;//    }////}

Prim

package com.dataStructure.weight_graph;import com.dataStructure.heap.IndexMinHeap;import java.util.ArrayList;import java.util.List;public class PrimMST {    private WeightedGraph graph;    // 存放输入的图    private boolean[] visited;  // 节点的访问状态    private IndexMinHeap indexMinHeap;  // 最小索引堆    private Edge[] edgeTo;  // edgeTo[i] 表示到 i 节点的 Edge    private List<Edge> mst; // 组成最小生成树的边    private Number mstWeight;   // 最小生成树的权重    // 构造函数    public PrimMST(WeightedGraph graph) {        // 私有字段初始化        this.graph = graph;        visited = new boolean[graph.V()];        indexMinHeap = new IndexMinHeap(graph.V());        edgeTo = new Edge[graph.V()];        mst = new ArrayList<>();        mstWeight = 0;        for (int i = 0; i < graph.V(); i++) {//            visited[i] = false;            edgeTo[i] = null;        }        // Prim        visit(0);   // 访问节点 0        while (!indexMinHeap.isEmpty()) {    // 最小索引堆不为空            int i = indexMinHeap.extractMinIndex(); // 获取当前堆中最小权重对应的节点            mst.add(edgeTo[i]); // 将 edgeTo[i] 加入 mst 中            visit(i);   // 访问节点 i        }        for (Edge edge : mst) // 计算最小生成树的权重            mstWeight = mstWeight.doubleValue() + edge.getWeight().doubleValue();    }    public void visit(int i) {        visited[i] = true;  // 节点的访问状态置为 true        for (Edge edge : graph.adjacentNode(i)) { // 遍历 i 的邻接节点            int w = edge.getAnotherNode(i);            if (!visited[w]) {   // 对于未被访问的邻接节点 w                if (edgeTo[w] == null) { // 如果尚未考虑过 w                    edgeTo[w] = edge;   // 设置到 w 的边为 edge                    indexMinHeap.insert(w, (Comparable) edge.getWeight());  // 插入到最小索引堆中                } else if (edge.compareTo(edgeTo[w]) < 0) {   // 如果考虑过 w                    // 且 edge 比 edgeTo[w] 的权重更小                    edgeTo[w] = edge;   // 更新到 w 的边为 edge                    indexMinHeap.change(w, (Comparable) edge.getWeight());  // 更新最小索引堆中 w 对应值                }            }        }    }    public List<Edge> getMst() {        return mst;    }    public Number getMstWeight() {        return mstWeight;    }    // 测试 Prim    public static void main(String[] args) {        String filename = "/testG1.txt";        int V = 8;        SparseGraph g = new SparseGraph(V, false);        ReadWeightedGraph readGraph = new ReadWeightedGraph(g, filename);        // Test Prim MST        System.out.println("Test Prim MST:");        PrimMST primMST = new PrimMST(g);        List<Edge> mst = primMST.getMst();        for (int i = 0; i < mst.size(); i++)            System.out.println(mst.get(i));        System.out.println("The MST weight is: " + primMST.getMstWeight());        System.out.println();    }}//public class PrimMST {//    private WeightedGraph G;              // 图的引用//    private IndexMinHeap ipq;     // 最小索引堆, 算法辅助数据结构//    private Edge[] edgeTo;        // 访问的点所对应的边, 算法辅助数据结构//    private boolean[] marked;             // 标记数组, 在算法运行过程中标记节点i是否被访问//    private List<Edge> mst;     // 最小生成树所包含的所有边//    private Number mstWeight;             // 最小生成树的权值////    // 构造函数, 使用Prim算法求图的最小生成树//    public PrimMST(WeightedGraph graph) {////        G = graph;//        assert (graph.E() >= 1);//        ipq = new IndexMinHeap(graph.V());////        // 算法初始化//        marked = new boolean[G.V()];//        edgeTo = new Edge[G.V()];//        for (int i = 0; i < G.V(); i++) {//            marked[i] = false;//            edgeTo[i] = null;//        }//        mst = new ArrayList<>();////        // Prim//        visit(0);//        while (!ipq.isEmpty()) {//            // 使用最小索引堆找出已经访问的边中权值最小的边//            // 最小索引堆中存储的是点的索引, 通过点的索引找到相对应的边//            int v = ipq.extractMinIndex();//            assert (edgeTo[v] != null);//            mst.add(edgeTo[v]);//            visit(v);//        }////        // 计算最小生成树的权值//        mstWeight = mst.get(0).getWeight();//        for (int i = 1; i < mst.size(); i++)//            mstWeight = mstWeight.doubleValue() + mst.get(i).getWeight().doubleValue();//    }////    // 访问节点v//    void visit(int v) {////        assert !marked[v];//        marked[v] = true;////        // 将和节点v相连接的未访问的另一端点, 和与之相连接的边, 放入最小堆中//        for (Edge edge : G.adjacentNode(v)) {//            int w = edge.getAnotherNode(v);//            // 如果边的另一端点未被访问//            if (!marked[w]) {//                // 如果从没有考虑过这个端点, 直接将这个端点和与之相连接的边加入索引堆//                if (edgeTo[w] == null) {//                    edgeTo[w] = edge;//                    ipq.insert(w, (Comparable)edge.getWeight());//                }//                // 如果曾经考虑这个端点, 但现在的边比之前考虑的边更短, 则进行替换//                else if (edge.compareTo(edgeTo[w]) < 0) {//                    edgeTo[w] = edge;//                    ipq.change(w, (Comparable)edge.getWeight());//                }//            }//        }////    }////    // 返回最小生成树的所有边//    List<Edge> mstEdges() {//        return mst;//    }////    // 返回最小生成树的权值//    Number result() {//        return mstWeight;//    }//////    // 测试 Prim//    public static void main(String[] args) {////        String filename = "/testG1.txt";//        int V = 8;////        SparseGraph g = new SparseGraph(V, false);//        ReadWeightedGraph readGraph = new ReadWeightedGraph(g, filename);////        // Test Prim MST//        System.out.println("Test Prim MST:");//        PrimMST primMST = new PrimMST(g);//        List<Edge> mst = primMST.mstEdges();//        for (int i = 0; i < mst.size(); i++)//            System.out.println(mst.get(i));//        System.out.println("The MST weight is: " + primMST.result());////        System.out.println();//    }////}

阅读全文
0 0
原创粉丝点击