【数据结构与算法】java有向带权图最短路径算法-Dijkstra算法(通俗易懂)

news2024/9/22 15:31:41

目录

  • 一、什么是Dijkstra算法
  • 二、算法基本步骤
  • 三、java代码
  • 四、拓展(无向图的Dijkstra算法)

一、什么是Dijkstra算法

Dijkstra算法的核心思想是通过逐步逼近的方式,找出从起点到图中其他所有节点的最短路径。算法的基本步骤如下:

举个例子:

在这里插入图片描述

如图所示的V1-V6六个点及他们的有向权重连线,现在我们假设从V1点出发,画出从顶点V1到其余各点最短路径的过程:

首先,我们将V1拿出来,V1能通向V2和V3,V1到V1的距离我们可以看成0,V1到V2的距离是10,V1到V3的距离是12,V1不能直接到达V4,V5,V6,我们可以看成是无穷大,那么V1的上一个结点是V1,V2和V3的上一个结点也是V1。V4,V5,V6此是没有连接结点记为-1,得到如下表格

在这里插入图片描述

然后根据距离数组{0,10,12,∞,∞,∞},找出数组中距离最小的值,即V2的10,我们将V2拿出来放到数组S中,则数组V中还剩余{V3,V4,V5,V6},现在我们取出了V1,V2;V1到V1和V2的位置还是没有变,取出V2后,V1到V3没有新的通路,所以距离还是12,所以V3的上一个点还是V1;V4和V5是可以根据V2进行跟新的,V4=10+16=26,V5=10=25=35,我们取出了V1,V2,到V6还是没有路线可以走,所以更新之后的表格如下:

在这里插入图片描述

我们距离数组{0,10,12,26,35,∞}中,选取最小值,即12的V3结点加入数组S中,数组V为{V4,V5,V6},现在加入的结点为V1、V2、V3,现在V1到V2的路线多出来V1-V3-V2,但是总长度是15比原本的10要大啊,所以不做变化,V1到V3的距离还是12,V1-V4有两条路(V1-V2-V4)和(V1-V3-V4)跟新后的V1-V3-V4距离是24比原来的26更短,所以替换之,然后V4上一个点的坐标就变成了V3,我们再看一下V1-V5,(V1-V2-V5)和(V1-V3-V2-V5)显然还是原本的35是最短距离;V1-V6的路径是(V1-V3-V6)距离是20,更新表格:

在这里插入图片描述

我们在数组{0,10,12,24,35,20}可以看出在去掉V1、V2、V3之后最小的点是V6的20,所以我们将V6加入到数组S中,V1到V1、V2、V3的距离保持不变;V1到V4的,因为增加了V6,所以多出来一条V1-V3-V6-V4,距离是22,比之前的24小,进行更新,所以V4的上一个结点变成V6;然后V1到V5,多增加路线V1-V3-V6-V5,总体距离变成30,比之前的35要小,更新表格,V5的上一个结点变成V6,跟新后的表格:

在这里插入图片描述

从数组V中取出距离最短的值V4放入数组S中,此时,V1到V1、V2、V3、V4的距离保持不变,V1-V5的距离多了一条V1-V3-V6-V4-V5,路径从29比以前的30要短,更新表格,所以V5的上一个结点的V4,V1-V6保持不变,更新后表格如下:

在这里插入图片描述
将最后一个点V5添加到数组S中,V5没有到其他点的新路径,所以dist[]和path[]数组不变。

如果想要知道V1到V6的距离:

先看path[],V6的上一个结点时V3,V3的上一个结点是V1,所以V1到V6的路径是V1-V3-V6;由dist[]数组得知距离权重是20;

如果想要知道V1到V5的距离:

先看path[],V5的上一个结点时V4,V4的上一个结点时V6,V6的上一个结点时V3,V3的上一个结点是V1,所以V1到V5的路径是V1-V3-V6-V4-V5;由dist[]数组得知距离权重是29;

其他的以此类推;

二、算法基本步骤

  1. 初始化:
  • 创建一个最短路径信息数组shortPath[x][3],每一个一维数组含义为当前结点、该节点到此节点的最短路径、起始节点。
  • 初始化shortPath数组,shortPath[x][0]当前节点编号、shortPath[x][1]最短路径、shortPath[x][2]起始结点编号
  • 初始化优先队列,将起始节点的所有邻接点加入到优先队列中,结点信息使用Ownership类,属性值{time、nodeIndex、weight}。
  • 创建优先队列,优先队列按照结点的权重值优先出队 PriorityQueue。
  • 创建优先队列的比较器OwnershipCustomerComparator类,通过weight大小进行优先出队。
  1. 流程:
  • 优先队列为空则退出
  • 遍历优先队列,将队列中time版本对应的结点信息值写入shortPath中。每次拿到最新路径长度newWeight=matrix[up - 1][ownership.nodeIndex] + shortPath[up - 1][1](起始节点最短路径+起始节点到当前节点一条边的权重),如果当前结点未被初始化则直接将newWeight写入shortPath数组中,如果当前节点已经被写过最短路径,则直接略过当前newWeight即可,这里有一个dtx变量,记录当前优先队列中结点是否被写如果shortPath,用于time(版本)。
  • 遍历优先队列(需要出队),将权重最小的结点出队,将该节点下的所有邻接点拿出做以下操作步骤:
    • 需要是出对节点的邻接点
    • 邻接点在shortPath表中的最短路径未被初始化(还是无穷大),将结点信息写入,最短路径为出对节点权重+出对节点到达该邻接点的权重
    • 查看该邻接点是否出现在优先队列中。在优先队列中则更新shortPath数组以及优先队列中该结点的权重以及起始节点的信息。
    • 优先队列中没有,Math.min(newWeight, shortPath[i][1]),取最优路径写入

三、java代码

代码地址:GitHub

算法代码:

public class Dijkstra {
    private Queue visited;
    int[] distance;

    public Dijkstra(int len) {
        // TODO Auto-generated constructor stub
        visited = new LinkedList();
        distance = new int[len];

    }

    private int getIndex(Queue q, int[] dis) {
        int k = -1;
        int min_num = Integer.MAX_VALUE;
        for (int i = 0; i < dis.length; i++) {
            if (!q.contains(i)) {
                if (dis[i] < min_num) {
                    min_num = dis[i];
                    k = i;
                }
            }
        }
        return k;
    }

    public void dijkstra(int[][] weight, Object[] str, int v) {
        HashMap path;
        path = new HashMap();
        for (int i = 0; i < str.length; i++)
            path.put(i, "");

        //初始化路径长度数组distance
        for (int i = 0; i < str.length; i++) {
            path.put(i, path.get(i) + "" + str[v]);
            if (i == v)
                distance[i] = 0;
            else if (weight[v][i] != -1) {
                distance[i] = weight[v][i];
                path.put(i, path.get(i) + "-->" + str[i]);
            } else
                distance[i] = Integer.MAX_VALUE;
        }
        visited.add(v);
        while (visited.size() < str.length) {
            int k = getIndex(visited, distance);//获取未访问点中距离源点最近的点
            visited.add(k);
            if (k != -1) {

                for (int j = 0; j < str.length; j++) {
                    //判断k点能够直接到达的点
                    if (weight[k][j] != -1) {
                        //通过遍历各点,比较是否有比当前更短的路径,有的话,则更新distance,并更新path。
                        if (distance[j] > distance[k] + weight[k][j]) {
                            distance[j] = distance[k] + weight[k][j];
                            path.put(j, path.get(k) + "-->" + str[j]);
                        }
                    }

                }
            }
        }
        for (int h = 0; h < str.length; h++) {
            System.out.printf(str[v] + "-->" + str[h] + ":" + distance[h] + " ");
            if (distance[h] == Integer.MAX_VALUE)
                System.out.print(str[v] + "-->" + str[h] + "之间没有可通行路径");
            else
                System.out.print(str[v] + "-" + str[h] + "之间有最短路径,具体路径为:" + path.get(h).toString());
            System.out.println();
        }
        visited.clear();

    }
}

测试代码:

public static void main(String[] args) {
        // TODO Auto-generated method stub
        int[][] weight = {
                {0, 10, 12, -1, -1, -1},
                {-1, 0, -1, 16, 25, -1},
                {4, 3, 0, 12, -1, 8},
                {-1, -1, -1, 0, 7, -1},
                {-1, -1, -1, -1, 0, -1},
                {-1, -1, -1, 2, -1, 0}};
        String[] str = {"V1", "V2", "V3", "V4", "V5", "V6"};
        int len = str.length;
        Dijkstra dijkstra = new Dijkstra(len);
        //依次让各点当源点,并调用dijkstra函数
        for (int i = 0; i < str.length; i++) {
            dijkstra.dijkstra(weight, str, i);
        }
    }

测试结果:
在这里插入图片描述

四、拓展(无向图的Dijkstra算法)

有向图问题解决了,无向图道理和有向图类似,例如如下的无向图,找出V1到其他个点的最短路径

在这里插入图片描述
我们只需要在Test类中定义一个无向图数组

int[][] undirected_weight = {
        {0,3,-1,7,-1},
        {3,0,4,2,-1},
        {-1,4,0,5,4},
        {7,2,5,0,6},
        {-1,-1,4,6,0}};
String[] str = {"V1", "V2", "V3", "V4", "V5"};

最后运行结果:

在这里插入图片描述

觉得有用的话还请多多点赞、收藏、评论!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1545879.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Simple negative sampling for link prediction inknowledge graphs

摘要 知识图嵌入方法学习知识图中实体和关系的低维向量表示&#xff0c;便于知识图中的链接预测任务。在学习嵌入过程中&#xff0c;采样负三元组是很重要的&#xff0c;因为KGs只观察到正三元组。据我们所知&#xff0c;均匀随机、基于生成对抗网络(GAN)和nscach、结构感知负…

PTA由斜杠划分区域

在由 1 x 1 方格组成的 N x N 网格 grid 中&#xff0c;每个 1 x 1 方块由 /、\ 或空格构成。这些字符会将方块划分为一些共边的区域。 返回区域的数目。 输入格式: 第一行输入一个正整数N&#xff08;N<30&#xff09; 随后N行&#xff0c;每行输入一个长度为N的字符串…

基于单片机的太阳能充电系统设计

摘要:本文所设计的太阳能充电系统主要由以下几个模块组成:STC89C52 主控模块、TP4056 充电电路、电压AD 采集模块、LCD1602 液晶显示模块和太阳能充电电池等组成。此太阳能充电器制作简单,性价比高,性能稳定。 关键词:LCD1602;太阳能充电系统;ADC0832 太阳能充电系统的充…

DARTS-: ROBUSTLY STEPPING OUT OF PERFORMANCE COLLAPSE WITHOUT INDICATORS

DARTS-&#xff1a;增加辅助跳跃连接&#xff0c;鲁棒走出搜索性能崩溃 论文链接&#xff1a;https://arxiv.org/abs/2009.01027 项目链接&#xff1a;GitHub - Meituan-AutoML/DARTS-: Code for “DARTS-: Robustly Stepping out of Performance Collapse Without Indicators…

分页多线程处理大批量数据

1.业务场景 因为需要从一个返利明细表中获取大量的数据&#xff0c;生成返利报告&#xff0c;耗时相对较久&#xff0c;作为后台任务执行。但是后台任务如果不用多线程处理&#xff0c;也会要很长时间才能处理完。 另外考虑到数据量大&#xff0c;不能一次查询所有数据在内存…

华为数通方向HCIP-DataCom H12-821题库(多选题:201-220)

第201题 以下关于BGP中Orginator ID属性的描述,正确的是哪些项? A、Originator ID属于公认任意属性 B、当其他BGP Speaker接收到这条路由的时候,将比较收到的0nginator ID和本地的Router ID,如果两个ID相同BGP Speaker会忽略掉这条路由,不做处理 C、当一条路由第一次被RR…

【目标检测】NMS算法的理论讲解

将NMS就必须先讲IOU&#xff0c; IOU就是交并比&#xff0c;两个检测框的交集除以两个检测框的并集就是IOU 为什么要做NMS操作&#xff0c;因为要去除同一个物体的多的冗余检测框 那么NMS算法是如何做的呢&#xff1f; 以上是算法的流程图 下面讲解算法的流程 首先输入是预…

爬虫Day3

用到的网页--豆瓣电影Top250 需要爬取信息&#xff1a; 数据保存在网页源代码中&#xff0c;是服务加载方式。先拿到网页源代码--request。再通过re提取想要的信息---re。 新知识&#xff1a;用csv存数据&#xff0c;可以用excel表格展示数据 import csv result obj.findite…

串口通信标准RS232 RS485 RS422的区别

RS-232、RS-422、RS-485是关于串口通讯的一个机械和电气接口标准&#xff08;顶多是网络协议中的物理层&#xff09;&#xff0c;不是通讯协议&#xff0c;它们之间的几个不同点如下&#xff1a; 一、硬件管脚接口定义不同 二、工作方式不同 RS232&#xff1a; 3线全双工 RS…

element UI季度选择器的实现

效果展示 用elementUI的select实现季度选择器 代码实现 generateQuarterOption放在methods中&#xff0c;需要近几年的只需要修改第一个循环的次数即可&#xff0c;mounted生命周期函数中调用generateQuarterOption() generateQuarterOption() {//近3年所有季度let now ne…

深入解析以太坊Dencun升级:提升网络性能与安全的关键举措

近年来&#xff0c;以太坊网络一直在不断演进和发展&#xff0c;为了应对日益增长的用户需求和挑战&#xff0c;以太坊社区不断提出并实施各种升级和改进措施。其中&#xff0c;Dencun升级作为最新的一项重大改革&#xff0c;旨在提升以太坊网络的性能和安全性&#xff0c;为其…

护眼台灯有必要买贵的吗?看看业内人士推荐的这五款!

随着学习压力的增大和担心孩子的近视&#xff0c;很多家长朋友们除了培养孩子正确的用眼习惯之外&#xff0c;也开始关注或准备添置学习用的护眼台灯&#xff0c;以缓解学习工作时的用眼疲劳&#xff0c;而相关的护眼灯也成为了市场的热门产品。而市面上护眼灯品牌众多&#xf…

CUDA从入门到放弃(四):CUDA 编程模式 CUDA Programming Model

CUDA从入门到放弃&#xff08;四&#xff09;&#xff1a;CUDA 编程模式 CUDA Programming Model 1 Kernels CUDA C 扩展了 C&#xff0c;允许定义名为内核的函数&#xff0c;这些函数可以被不同的 CUDA 线程并行执行多次&#xff0c;而不是像普通 C 函数那样只执行一次。内核…

【2024.3.26练习】画中漂流

题目描述 题目分析 根据题型分析应该可以用动态规划解决。设为第秒&#xff0c;剩余体力值为&#xff0c;且当前位置距离峡谷米时的总方案数。根据题意&#xff0c;状态转移方程如下&#xff1a; 这样定义状态的话空间复杂度为&#xff0c;大大超出了空间限制。观察转移方程左…

【SpringBoot】实现一个简单的图片上传

前端上传表单 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> <body> <form enctype"multipart/form-data" method"post" action&q…

拓展AI边界:去中心化人工智能的应用场景和主要项目盘点

随着区块链技术的发展和普及&#xff0c;去中心化人工智能&#xff08;AI&#xff09;逐渐成为技术领域的焦点之一。区块链的去中心化特性为AI技术的应用提供了新的可能性&#xff0c;使得数据共享、模型训练和应用部署更加安全、透明和可靠。本文将探索去中心化AI的应用场景&a…

【NLP学习记录】Embedding和EmbeddingBag

Embedding与EmbeddingBag详解 ●&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客 ●&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 ●&#x1f680; 文章来源&#xff1a;K同学的学习圈子1、Embedding详解 Embedding是Pytorch中最基本…

Spring实例化Bean的三种方式

参考资料&#xff1a; Core Technologies 核心技术 spring实例化bean的三种方式 构造器来实例化bean 静态工厂方法实例化bean 非静态工厂方法实例化bean_spring中有参构造器实例化-CSDN博客 1. 构造函数 1.1. 空参构造函数 下面这样表示调用空参构造函数&#xff0c;使用p…

Mysql数据库函数【Mysql】

Mysql数据库函数【Mysql】 前言版权Mysql数据库函数常用函数排序与分页排序分页 单行函数2.数值函数2.1基本函数2.2角度与弧度2.3三角函数2.4指数与对数函数2.5进制间的转换 3.字符串函数4.日期和时间函数4.1获取日期、时间4.2日期与时间戳的转换4.3获取月份、星期、星期数、天…

C语言数据流讲解

目录 4.1 流&#xff08;Stream&#xff09;&#xff1a;数据流动的隐喻 4.1.1 流&#xff1a;数据传输的通用接口 4.1.2 标准流&#xff1a;预定义的流通道 4.2 文件指针&#xff1a;流操作的桥梁 4.2.1 文件指针的本质与结构 4.2.2 使用文件指针操作流 图解 结语 在C…