普里姆算法之JAVA实现

普里姆算法是用来求加权连通图中的最小(代价)生成树的算法。

普里姆算法的基本思想是:从图中任意取出一个顶点,把它当成一棵树,然后从与这棵树相接的边中选取一条权值最小的边,并将这条边及其所连接的顶点一同并入这棵树中,重复以上操作,直到所有的顶点都被并入到这棵树中为止。

容易看到,这里有一个递归重复进行的过程,所以可以采用递归的思想来完成该算法。

首先,需要构造一个图结构,本文以如下图为图结构
普里姆算法之JAVA实现_第1张图片图的顶点定义如下:

iimport java.util.ArrayList;
import java.util.List;

//表示图的顶点
public class GraphNode {
    // 表示该顶点的数据
    private String data;
    // 表示该顶点的边集合
    public List<GraphEdge> nodeList = null;
    // 表示该顶点是否被访问过
    private boolean isVisited;
    // 构造方法
    public GraphNode(String data) {
        this.data = data;
        isVisited = false;
        if (nodeList == null) {
            nodeList = new ArrayList<>();
        }
    }

    public String getData() {
        return data;
    }

    public List<GraphEdge> getEdgeList() {
        return nodeList;
    }

    public void setVisited(boolean isVisited) {
        this.isVisited = isVisited;
    }

    public boolean isVisited() {
        return isVisited;
    }
}


图的边定义如下:

// 表示图的边
public class GraphEdge {
    // 该边连接的左顶点
    private GraphNode leftNode;
    // 该边连接的右顶点
    private GraphNode rightNode;

    // 边的权值
    private int weight;
    // 该边是否被访问
    private boolean isVisited;

    public GraphEdge(GraphNode leftNode, GraphNode rightNode, int weight) {
        this.leftNode = leftNode;
        this.rightNode = rightNode;
        this.weight = weight;
        isVisited = false;
    }

    public GraphNode getLeftNode() {
        return leftNode;
    }

    public GraphNode getRightNode() {
        return rightNode;
    }

    public int getWeight() {
        return weight;
    }

    public boolean isVisited() {
        return isVisited;
    }
    public void setVisited(boolean isVisited) {
        this.isVisited = isVisited;
    }
}

构造图的代码放在main函数中:

    public static void main(String[] args) {
        GraphNode A = new GraphNode("A");
        GraphNode B = new GraphNode("B");
        GraphNode C = new GraphNode("C");
        GraphNode D = new GraphNode("D");
        GraphNode E = new GraphNode("E");
        GraphEdge AB = new GraphEdge(A, B, 2);
        GraphEdge AC = new GraphEdge(A, C, 4);
        GraphEdge AD = new GraphEdge(A, D, 2);
        GraphEdge BC = new GraphEdge(B, C, 3);
        GraphEdge CD = new GraphEdge(C, D, 3);
        GraphEdge BE = new GraphEdge(B, E, 3);
        GraphEdge CE = new GraphEdge(C, E, 4);
        GraphEdge DE = new GraphEdge(D, E, 5);
        A.getEdgeList().add(AB);
        A.getEdgeList().add(AC);
        A.getEdgeList().add(AD);
        B.getEdgeList().add(AB);
        B.getEdgeList().add(BC);
        B.getEdgeList().add(BE);
        C.getEdgeList().add(AC);
        C.getEdgeList().add(BC);
        C.getEdgeList().add(CD);
        C.getEdgeList().add(CE);
        D.getEdgeList().add(AD);
        D.getEdgeList().add(CD);
        D.getEdgeList().add(DE);
        E.getEdgeList().add(BE);
        E.getEdgeList().add(CE);
        E.getEdgeList().add(DE);
    }


这段代码可以完成图的构建。
接下来是普里姆算法的代码:

static int sum = 0;

static void prim(List<GraphNode> nodes, int size) {
    if (nodes.size() == size)
        return;
    int tmp = Integer.MAX_VALUE;
    int x = -1, y = -1;
    for (int i = 0; i < nodes.size(); i++) {
        List<GraphEdge> edges = nodes.get(i).getEdgeList();
        for (int j = 0; j < edges.size(); j++) {
            GraphEdge ge = edges.get(j);
            if (ge.isVisited() == true)
                continue;
            if (ge.getWeight() <= tmp) {
                tmp = ge.getWeight();
                x = i;
                y = j;
            }
        }
    }
    GraphEdge ge = nodes.get(x).getEdgeList().get(y);
    ge.setVisited(true);
    sum += ge.getWeight();
    if (!ge.getLeftNode().isVisited()) {
        nodes.add(ge.getLeftNode());
        ge.getLeftNode().setVisited(true);
    }
    if (!ge.getRightNode().isVisited()) {
        nodes.add(ge.getRightNode());
        ge.getRightNode().setVisited(true);
    }
    prim2(nodes, size);
}

um用来求最后生成的最小生成树的权值和。
prim()方法就是实现普里姆算法的代码,这个方法接收一个list,这个list中的点就是每一次生成的树包含的所有节点
(1)初始值只有一个节点:出发节点。出发节点可以任选
(2)然后prim()方法就是从接收的list中遍历所有节点的所有相接的边,选取权值最小的一条,如果权值最小有多条,则任意选一条即可。
(3)选定权值最小的那条边后,就把这条边的另一个节点加到list中并设置状态已被访问,然后设置该边也已被访问
(4)这时,list中就多了一个节点,递归调用prim()方法即可。递归的终止条件就是list中包含了所有的节点,也就是代码中的nodes.size() == size。

作者:月光下一只赏月的猪
原文:https://blog.csdn.net/qq_16403141/article/details/80422157

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