Java手写Prim算法和Prim算法应用拓展案例

2023-09-19 23:17:06

Java手写Prim算法和Prim算法应用拓展案例

1. 算法思维导图

以下是使用Mermanid代码表示的Prim算法实现原理:

2. 该算法的手写必要性和市场调查

手写Prim算法的必要性在于深入理解算法的原理和实现细节,从而能够更好地应用和优化该算法。市场调查显示,Prim算法在网络规划、最小生成树问题等领域有着广泛的应用,具有很高的市场需求和潜力。

3. 该算法的详细介绍和步骤

Prim算法是一种用于解决最小生成树问题的贪心算法。它从一个节点开始,逐步扩展生成树,直到包含所有节点为止。以下是Prim算法的详细步骤:

  1. 初始化图G和集合S,将任意节点加入S。
  2. 初始化边集E,将与S中节点相连的边加入E。
  3. 从E中选择权值最小的边e,并将其加入到集合T中。
  4. 将e的另一端节点加入S。
  5. 将与新加入S中的节点相连的边加入E。
  6. 重复步骤3到5,直到S包含所有节点。

4. 该算法的手写实现总结和思维拓展

通过手写实现Prim算法,我们深入理解了算法的原理和实现细节。该算法的思维拓展可以包括以下方面:

  • 优化算法的时间复杂度和空间复杂度。
  • 将算法应用于不同类型的图结构。
  • 探索其他贪心算法和最小生成树算法的联系和区别。

5. 该算法的完整代码

以下是Java语言实现的Prim算法的完整代码,每行代码都附有注释:

import java.util.*;

public class PrimAlgorithm {
    public static void main(String[] args) {
        // 构建图的邻接矩阵表示
        int[][] graph = {
            {0, 2, 0, 6, 0},
            {2, 0, 3, 8, 5},
            {0, 3, 0, 0, 7},
            {6, 8, 0, 0, 9},
            {0, 5, 7, 9, 0}
        };

        prim(graph);
    }

    public static void prim(int[][] graph) {
        int n = graph.length; // 图的节点数

        int[] parent = new int[n]; // 保存最小生成树的父节点
        int[] key = new int[n]; // 保存节点到最小生成树的最小权值

        boolean[] visited = new boolean[n]; // 记录节点是否已经访问过

        // 初始化key数组为无穷大
        Arrays.fill(key, Integer.MAX_VALUE);

        // 从第一个节点开始构建最小生成树
        key[0] = 0;
        parent[0] = -1;

        for (int i = 0; i < n - 1; i++) {
            int minKeyIndex = findMinKey(key, visited); // 找到key数组中最小值对应的节点

            visited[minKeyIndex] = true; // 将该节点标记为已访问

            // 更新与该节点相邻的节点的key值和parent值
            for (int j = 0; j < n; j++) {
                if (graph[minKeyIndex][j] != 0 && !visited[j] && graph[minKeyIndex][j] < key[j]) {
                    parent[j] = minKeyIndex;
                    key[j] = graph[minKeyIndex][j];
                }
            }
        }

        // 输出最小生成树
        System.out.println("边\t权值");
        for (int i = 1; i < n; i++) {
            System.out.println(parent[i] + " - " + i + "\t" + graph[i][parent[i]]);
        }
    }

    public static int findMinKey(int[] key, boolean[] visited) {
        int minKey = Integer.MAX_VALUE;
        int minKeyIndex = -1;

        for (int i = 0; i < key.length; i++) {
            if (!visited[i] && key[i] < minKey) {
                minKey = key[i];
                minKeyIndex = i;
            }
        }

        return minKeyIndex;
    }
}

6. 该算法的应用前景调研

Prim算法作为一种解决最小生成树问题的常用算法,具有广泛的应用前景。它可以应用于以下领域:

  • 网络规划:Prim算法可以用于构建网络拓扑结构,以实现最小成本的网络连接。
  • 电力系统:Prim算法可以用于优化电力系统的供电路径,以提高电力传输效率。
  • 物流管理:Prim算法可以用于优化物流路径,以降低物流成本和提高物流效率。

7. 该算法的拓展应用案例

以下是Prim算法的三个拓展应用案例的完整代码和步骤描述:

7.1 案例1: 最小生成树的可视化

import java.awt.*;
import java.util.*;
import javax.swing.*;

public class PrimVisualization extends JPanel {
    private static final int WIDTH = 800;
    private static final int HEIGHT = 600;
    private static final int RADIUS = 20;

    private int[][] graph;
    private Set<Integer> minTree;
    private Set<Integer> visited;

    public PrimVisualization(int[][] graph) {
        this.graph = graph;
        this.minTree = new HashSet<>();
        this.visited = new HashSet<>();
        this.setPreferredSize(new Dimension(WIDTH, HEIGHT));

        prim();
    }

    private void prim() {
        int n = graph.length;
        int[] parent = new int[n];
        int[] key = new int[n];
        boolean[] inTree = new boolean[n];

        Arrays.fill(key, Integer.MAX_VALUE);

        key[0] = 0;
        parent[0] = -1;

        for (int i = 0; i < n - 1; i++) {
            int u = findMinKey(key, inTree);
            inTree[u] = true;

            for (int v = 0; v < n; v++) {
                if (graph[u][v] != 0 && !inTree[v] && graph[u][v] < key[v]) {
                    parent[v] = u;
                    key[v] = graph[u][v];
                }
            }
        }

        for (int i = 1; i < n; i++) {
            minTree.add(parent[i]);
            minTree.add(i);
        }
    }

    private int findMinKey(int[] key, boolean[] inTree) {
        int minKey = Integer.MAX_VALUE;
        int minKeyIndex = -1;

        for (int i = 0; i < key.length; i++) {
            if (!inTree[i] && key[i] < minKey) {
                minKey = key[i];
                minKeyIndex = i;
            }
        }

        return minKeyIndex;
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        int n = graph.length;

        // 绘制节点
        for (int i = 0; i < n; i++) {
            int x = (i % 4 + 1) * WIDTH / 5;
            int y = (i / 4 + 1) * HEIGHT / 3;
            g.setColor(minTree.contains(i) ? Color.RED : Color.BLACK);
            g.fillOval(x - RADIUS, y - RADIUS, 2 * RADIUS, 2 * RADIUS);
            g.setColor(Color.WHITE);
            g.drawString(String.valueOf(i), x - 5, y + 5);
        }

        // 绘制边
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                if (graph[i][j] != 0) {
                    int x1 = (i % 4 + 1) * WIDTH / 5;
                    int y1 = (i / 4 + 1) * HEIGHT / 3;
                    int x2 = (j % 4 + 1) * WIDTH / 5;
                    int y2 = (j / 4 + 1) * HEIGHT / 3;
                    g.setColor(minTree.contains(i) && minTree.contains(j) ? Color.RED : Color.BLACK);
                    g.drawLine(x1, y1, x2, y2);
                }
            }
        }
    }

    public static void main(String[] args) {
        int[][] graph = {
            {0, 2, 0, 6, 0},
            {2, 0, 3, 8, 5},
            {0, 3, 0, 0, 7},
            {6, 8, 0, 0, 9},
            {0, 5, 7, 9, 0}
        };

        JFrame frame = new JFrame("Prim Visualization");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(new PrimVisualization(graph));
        frame.pack();
        frame.setVisible(true);
    }
}

7.2案例2: 最小生成树的路径规划

import java.util.*;

public class PrimPathPlanning {
    public static void main(String[] args) {
        int[][] graph = {
            {0, 2, 0, 6, 0},
            {2, 0, 3, 8, 5},
            {0, 3, 0, 0, 7},
            {6, 8, 0, 0, 9},
            {0, 5, 7, 9, 0}
        };

        int start = 0;
        int end = 4;

        List<Integer> path = primPath(graph, start, end);

        System.out.println("最小生成树路径:" + path);
    }

    public static List<Integer> primPath(int[][] graph, int start, int end) {
        int n = graph.length;
        int[] parent = new int[n];
        int[] key = new int[n];
        boolean[] inTree = new boolean[n];

        Arrays.fill(key, Integer.MAX_VALUE);

        key[start] = 0;
        parent[start] = -1;

        for (int i = 0; i < n - 1; i++) {
            int u = findMinKey(key, inTree);
            inTree[u] = true;

            for (int v = 0; v < n; v++) {
                if (graph[u][v] != 0 && !inTree[v] && graph[u][v] < key[v]) {
                    parent[v] = u;
                    key[v] = graph[u][v];
                }
            }
        }

        List<Integer> path = new ArrayList<>();
        int current = end;

        while (current != -1) {
            path.add(current);
            current = parent[current];
        }

        Collections.reverse(path);
        return path;
    }

    public static int findMinKey(int[] key, boolean[] inTree) {
        int minKey = Integer.MAX_VALUE;
        int minKeyIndex = -1;

        for (int i = 0; i < key.length; i++) {
            if (!inTree[i] && key[i] < minKey) {
                minKey = key[i];
                minKeyIndex = i;
            }
        }

        return minKeyIndex;
    }
}
更多推荐

js制作柱状图的x轴时间, 分别展示 月/周/日 的数据

背景有个需求是要做一个柱状图,x轴是时间,y轴是数量.其中x轴的时间有三种查看方式:月份/周/日,也就是分别查看从当前日期开始倒推的最近每月/每周/每日的数量.本篇文章主要是用来制作三种不同的x轴从当前月开始倒推月份注意getMonth()函数可以获取当前月份,但是范围是0-11,0代表1月letxArr=[];//用

SpringMVC----自定义注解

目录自定义注解是什么作用JDK元注解测试案列案例一(获取类与方法上的注解值)案例二(获取类属性上的注解属性值)案例三(获取参数修饰注解对应的属性值)五.Aop自定义注解的应用Mylog前置通知自定义注解是什么SpringMVC自定义注解是指开发者根据自己的需求,在SpringMVC框架中自定义的注解。通过自定义注解,可

哈希(hash)——【C++实现】

本章gitee代码仓库:Hash文章目录💐1.哈希概念🌻2.哈希冲突🌼3.哈希函数🌸3.1哈希函数设计原则🌸3.2常见哈希函数🪴4.哈希冲突解决方案🌱4.1闭散列——开放定址法🌿4.11负载因子🌿4.12字符串哈希算法🌿4.13代码实现🌱4.2开散列——哈希桶🌿4.21代码实现💐1.哈希概念我

系统集成|第九章(笔记)

目录第九章成本管理9.1成本管理概念及相关术语9.2主要过程9.2.1制订成本管理计划9.2.2成本估算9.2.3成本预算9.2.4成本控制上篇:第八章、进度管理第九章成本管理9.1成本管理概念及相关术语概述:项目成本管理就是要确保在批准的预算内完成项目项目成本失控的原因:①对项目认识不足②组织制度不健全③方法问题④技

LuatOS-SOC接口文档(air780E)--audio - 多媒体音频

常量常量类型解释audio.PCMnumberPCM格式,即原始ADC数据audio.MORE_DATAnumberaudio.on回调函数传入参数的值,表示底层播放完一段数据,可以传入更多数据audio.DONEnumberaudio.on回调函数传入参数的值,表示底层播放完全部数据了audio.BUS_DACnum

ES6的代理模式 | Proxy

🎬岸边的风:个人主页🔥个人专栏:《VUE》《javaScript》⛺️生活的理想,就是为了理想的生活!目录正文语法Handler对象常用的方法handler.get可撤消的ProxyProxy的应用场景校验器私有属性为什么要用Proxy重构Vue中的defineProperty对象新增属性为什么不更新数组变异对比p

开发项目的前后端分离,学习Vue的生命周期

目录一、概述(1)介绍1-1背景1-2是什么(2)库和框架的区别(3)MVVM与Vue3.1MVVM介绍3.2MVVM与Vue二、Vue入门三、生命周期3-1讲述3-2演示带给我们的收获一、概述(1)介绍1-1背景Vue的背景可以追溯到2013年,当时尤雨溪(EvanYou)是Google的工程师,负责开发Angula

Ubuntu修改静态IP、网关和DNS的方法总结

Ubuntu修改静态IP、网关和DNS的方法总结ubuntu系统(其他debian的衍生版本好像也可以)修改静态IP有以下几种方法。(搜索总结,可能也不太对)/etc/netplan(use)Ubuntu18.04开始可以使用netplan配置网络,其也是默认安装的。配置文件位于/etc/netplan/xxx.yam

深入实现 MyBatis 底层机制的实现任务阶段 7- 实现动态代理 Mapper 的方法

😀前言在Java世界里,MyBatis是一个优秀的持久层框架,它支持自定义SQL、存储过程以及高级映射。MyBatis消除了几乎所有的JDBC代码和参数的手动设置以及结果集的检索。MyBatis可以使用简单的XML或注解进行配置,并且能映射基本类型、Map接口及任何JavaPOJO(PlainOldJavaObjec

应用案例 | 使用dataFEED OPC Suite将汽车零部件工厂数据集成到SAP Business Suite

一背景某知名空气过滤和热管理组件供应商是一家专业的汽车零部件制造集团——专注于液体和空气过滤系统、进气系统以及热管理组件的生产与销售。该集团在全球范围内拥有24个生产工厂,并在运营中广泛采用了SAPBusinessSuite作为其企业资源规划(ERP)和制造执行系统(MES)。该集团的主要业务需求是将来自车间设备的生产

SpringSecurity 权限管理的实现

文章目录前言权限管理的实现权限校验的原理FilterSecurityInterceptorAccessDescisionManagerAffirmativeBasedConsensusBasedUnanimousBasedAccessDecisionVoterWebExpressionVoterAuthenticate

热文推荐