算法基础|prim算法的实现

该代码示例展示了如何在Java中实现Prim算法来找到图的最小生成树。程序首先定义了一个图类,包含顶点、边和权重等属性,并提供了添加顶点、插入边的方法。接着,通过prim()方法逐步构建最小生成树,通过遍历和比较所有边的权重来选择最小的边加入到当前的树中。最后,使用深度优先搜索(DFS)展示生成的树。
摘要由CSDN通过智能技术生成

import java.util.ArrayList;


/**
 * @author xiwang2017
 * @创建时间 2022/6/26 15:35
 * @描述 prim算法实现
 */
public class Prim_MST {

    public static void main(String[] args) {
        Graph graph = new Graph(7);
        char[] data = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G'};
        Node[][] edges = new Node[][]{//应该写个转换方法的,自己想ABC啥的下标太累人了
                {new Node(1, 5), new Node(2, 7), new Node(6, 2)},//A
                {new Node(0, 5), new Node(3, 9), new Node(6, 3)},
                {new Node(0, 7), new Node(4, 8)},
                {new Node(1, 9), new Node(5, 4)},//D
                {new Node(2, 8), new Node(5, 5), new Node(6, 4)},
                {new Node(3, 4), new Node(4, 5), new Node(6, 6)},//F
                {new Node(0, 2), new Node(1, 3), new Node(4, 4), new Node(5, 6)}
        };
        for (int i = 0; i < data.length; i++) {
            graph.add(data[i]);
            for (int j = 0; j < edges[i].length; j++) {
                graph.insertEdge(i, edges[i][j].sub, edges[i][j].weight);
            }
        }

        graph.dsf(0);
        Graph prim = graph.prim(0);
        prim.dsf(0);
        System.out.println(prim);

    }

}

class Graph {
    int E;//当前边数
    int N;//顶点数量
    int V;//当前顶点数量
    ArrayList<Node>[] edges;
    char[] data;//顶点数据,之前用的list存的,因为想着没法数组没法确认大小,但是我忘记了可以从构造器里面确定数组大小
    private int[] check;

    //构造器方法,将要用到的属性和容器初始化
    public Graph(int N) {
        this.N = N;
        V = 0;
        data = new char[N];
        edges = new ArrayList[N];
        check = new int[N];
        for (int i = 0; i < N; i++) {
            edges[i] = new ArrayList<>();
        }
    }

    //prim算法生成mst入口方法
    public Graph prim(int start) {
        Graph graph = new Graph(N);
        check[start] = 1;
        while (graph.E < N - 1) {//线的个数比顶点数少1,即N-1条线
            minOfPartGraph(graph);
        }
        check = new int[N];//用一次,还原一次,不然别的方法要用就会出错。
        return graph;
    }

    //找到局部图所连接的,权值最小的路径,然后将该路径添加入局部图中
    //调用一次,增长1个点以及点间最短的路径
    //实现方法是遍历局部图中所有的点,让该点调用minOfPoint()方法,得到该点所连接的最短路径
    //然后比较所有点返回的路径,得到一个最小路径,然后把路径添加入局部图中。
    //注意:数值传递时不要弄混,点的下标和权值一定要一一对应。
    public void minOfPartGraph(Graph graph) {
        //用于筛选用的属性
        int m = N + 1;
        int minSub = N + 1;
        int minWeight = Integer.MAX_VALUE;

        //遍历局部图与整体图相交的点,并找出路径权值最低的那个点
        //将两点间的线加入局部图中,让局部图增长
        for (int i = 0; i < check.length; i++) {
            if (check[i] == 1) {
                Node node = minOfPoint(i);
                if (node != null) {
                    int weight = node.weight;
                    if (minWeight > weight) {
                        minSub = node.sub;
                        minWeight = weight;
                        m = i;
                    }
                }
            }
        }
        check[minSub] = 1;
        graph.insertEdge(m, minSub, minWeight);
    }


    //找到该点连接着的,最小的路径的点,然后将该点的信息返回(顶点的下标和权值)
    //实现原理:遍历该点所连接的路径,从中挑选出一条最短的路径,然后返回该路径的信息
    //注意:遍历该点所连接点,必须是未到达过的(避免成环)
    public Node minOfPoint(int start) {
        ArrayList<Node> edge = edges[start];
        //应当做一些空及边界判断的事情,但是我这个是原型,就不搞了先
        int minWeight = Integer.MAX_VALUE;
        int minSub = N + 1;
        boolean flag = false;
        for (Node node : edge) {
            //要从这个node里面取出一个最小的weight
            //但是有个限定,即该点是未到达过的//如果这个点是到达过的,那么可能会添加重复的边,可能会形成环
            int sub = node.sub;
            if (check[sub] == 0) {
                flag = true;
                int weight = node.weight;
                if (weight < minWeight) {
                    minWeight = weight;
                    minSub = sub;
                }
            }
        }
        if (flag) {
            return new Node(minSub, minWeight);
        } else return null;


    }

    public void dsf(int i) {
        list_DFS(i);
        check = new int[N];
    }

    private void list_DFS(int i) {
        if (check[i] == 0) System.out.println("到达世界第" + i + "城," + data[i] + "城!");
        check[i] = 1;
        ArrayList<Node> list = edges[i];
        for (Node node : list) {
            if (check[node.sub] == 0) {
                list_DFS(node.sub);
            }
        }
    }

    public void insertEdge(int m, int n, int weight) {
        for (int i = 0; i < edges[m].size(); i++) {//解决重复添加问题
            if (edges[m].get(i).sub == n && edges[m].get(i).weight == weight) {
                return;
            }
        }
        edges[m].add(new Node(n, weight));
        edges[n].add(new Node(m, weight));
        E++;
    }

    public void add(char c) {
        data[V] = c;
        V++;
    }

}

class Node {
    int sub;
    int weight;

    public Node(int sub, int weight) {
        this.sub = sub;
        this.weight = weight;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值