Prim算法生成最小生成树(MST)原理及算法实现

一、目的

        本实验旨在理解和掌握Prim算法的基本原理,并通过编程实现该算法,以求解给定无向加权图的最小生成树。通过本实验,能够加深对最小生成树概念的理解,并提升编程能力

二、原理

        Prim算法是一种求解最小生成树的贪心算法。其基本原理是:从任意一个顶点开始,每次选择连接已选择的顶点集合与未选择的顶点集合之间的最短边,并将该边的另一个顶点加入已选择的顶点集合,直到所有顶点都被选择为止。最终,所选的边构成的就是最小生成树。

三、步骤

  1. 实现Prim算法

    • PrimMST类中实现Prim算法,包括:
  • 私有成员变量,包括顶点数量V、邻接矩阵graph、最短距离数组key、MST标记数组mstSet和父顶点数组parent
  • 构造函数,用于初始化图的顶点数量和相关数组。
  • prim方法,实现Prim算法的核心逻辑。
  • updateKey方法,用于更新key数组和优先队列。
  1. 编写主函数

    1. main方法中:
  • 创建Scanner对象以读取用户输入。
  • 读取顶点数量V和邻接矩阵。
  • 选择源顶点的索引。
  • 调用prim方法并传入源顶点索引。
  • 打印每个顶点到源顶点的最短距离。
  • 打印MST的边。

四、代码展示

package com.lwtstu5.practice;

import java.util.Scanner;
import java.util.PriorityQueue;

public class PrimMST {
    private int V; // 顶点的数量
    private int[][] graph; // 图的邻接矩阵表示
    private int[] key; // 存储每个顶点到MST的最短距离
    private boolean[] mstSet; // 标记顶点是否已经在MST中
    private int[] parent; // 存储MST中每个顶点的父顶点

    public PrimMST(int V) {
        this.V = V;
        this.graph = new int[V][V];
        this.key = new int[V];
        this.mstSet = new boolean[V];
        this.parent = new int[V];
    }

    // 构造函数、辅助函数等...

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("Enter the number of vertices");
        int V = scanner.nextInt();

        PrimMST pmst = new PrimMST(V);

        System.out.println("Enter the adjacency matrix:");
        for (int i = 0; i < V; i++) {
            for (int j = 0; j < V; j++) {
                pmst.graph[i][j] = scanner.nextInt();
            }
        }

        int src = 0; // 选择源顶点
        pmst.prim(src);

        System.out.println("Vertex \t Distance from Source");
        for (int i = 0; i < V; i++)
            System.out.println(i + " \t " + pmst.key[i]);

        // 输出MST的边
        System.out.println("Edges of the MST:");
        for (int i = 1; i < V; i++) {
            System.out.println(pmst.parent[i] + " - " + i + " (weight: " + pmst.graph[pmst.parent[i]][i] + ")");
        }

        scanner.close();
    }

    public void prim(int src) {
        for (int i = 0; i < V; i++) {
            key[i] = Integer.MAX_VALUE;
            mstSet[i] = false;
        }
        key[src] = 0;

        PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[1] - b[1]); // 边的权重作为优先级
        pq.offer(new int[]{src, 0}); // 顶点索引和权重

        while (!pq.isEmpty()) {
            int[] currEdge = pq.poll();
            int u = currEdge[0];
            if (!mstSet[u]) {
                mstSet[u] = true;
                updateKey(u, currEdge[1], pq);
            }
        }
    }

    private void updateKey(int src, int weight, PriorityQueue<int[]> pq) {
        for (int v = 0; v < V; v++) {
            if (graph[src][v] != 0 && !mstSet[v] && graph[src][v] < key[v]) {
                key[v] = graph[src][v];
                parent[v] = src;
                pq.offer(new int[]{v, graph[src][v]});
            }
        }
    }
}

五、测试结果

这个输出表示:

  • 顶点0到源顶点(它自己)的距离是0
  • 顶点1到源顶点的距离是1,这是通过边(0, 1)的权重。
  • 顶点2到源顶点的距离是3,这是通过边(1, 2)的权重。
  • 顶点3到源顶点的距离是4,这是通过边(2, 3)的权重。

MST的边是:

  • 顶点0到顶点1的边,权重为1
  • 顶点1到顶点2的边,权重为3
  • 顶点2到顶点3的边,权重为5
  • 10
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值