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

目录

  • 一、什么是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.mfbz.cn/a/490269.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【剑指offr--C/C++】JZ22 链表中倒数最后k个结点

一、题目 二、思路及代码 遍历链表并存入vector容器&#xff0c;通过下标取出对应位置元素或者返回空 /*** struct ListNode {* int val;* struct ListNode *next;* ListNode(int x) : val(x), next(nullptr) {}* };*/ #include <cstddef> #include <iterator> #…

轻松搞定!使用Python操作 xlsx 文件绘制饼图

今天&#xff0c;跟大家一起来学习用Python操作xlsx文件&#xff0c;然后绘制了一个饼图。你知道吗&#xff0c;这个过程居然比我想象中的还要简单&#xff01;只需要几行代码&#xff0c;就能轻松搞定&#xff01; 首先&#xff0c;安装一个叫做openpyxl的库&#xff0c;它可…

住在我心里的猴子:焦虑那些事儿 - 三余书屋 3ysw.net

精读文稿 您好&#xff0c;本期我们解读的是《住在我心里的猴子》。这是一本由患有焦虑症的作家所著&#xff0c;关于焦虑症的书。不仅如此&#xff0c;作者的父母和哥哥也都有焦虑症&#xff0c;而作者的母亲后来还成为了治疗焦虑症的专家。这本书的中文版大约有11万字&#x…

C++初阶:容器适配器stack与queue

目录 1. stack与queue的使用练习1.1 stack的常用接口&#xff08;栈&#xff09;1.2 queue常用接口&#xff08;队列&#xff09;1.3 priority_queue的常用接口&#xff08;堆&#xff09; 2. 容器适配器2.1 栈的实现2.2 队列的实现3. 堆&#xff08;priority_queue&#xff09…

在Python Matplotlib中让X轴标签向右对齐并且向右稍微移动一些距离

在Python Matplotlib中让X轴标签向右对齐并且向右稍微移动一些距离 在Matplotlib中画图时&#xff0c;当x轴标签很长时&#xff0c;我们通常会使用rotation对标签进行倾斜显示。但是这个时候有些标签&#xff08;长度过长的&#xff0c;例如很长的单词&#xff09;会重叠。这个…

MySQL驱动Add Batch优化实现

MySQL 驱动 Add Batch 优化实现 MySQL 驱动会在 JDBC URL 添加 rewriteBatchedStatements 参数时&#xff0c;对 batch 操作进行优化。本文测试各种参数组合的行为&#xff0c;并结合驱动代码简单分析。 batch参数组合行为 useServerPrepStmts 参数 PreparedStatement psmt…

设置MATLAB三维绘图的视角

MATLAB三维绘图plot3在生成绘图后&#xff0c;默认显示视角是斜着的&#xff1a; 使用view(2)命令可以使其转成XoY平面&#xff08;从上往下看的视角&#xff09;&#xff1a;

推荐多样性 - 华为OD统一考试(C卷)

OD统一考试&#xff08;C卷&#xff09; 分值&#xff1a; 200分 题解&#xff1a; Java / Python / C 题目描述 推荐多样性需要从多个列表中选择元素&#xff0c;一次性要返回N屏数据&#xff08;窗口数量&#xff09;&#xff0c;每屏展示K个元素&#xff08;窗口大小&#…

深度强化学习(十)(TRPO)

深度强化学习&#xff08;十&#xff09;&#xff08;TRPO与PPO&#xff09; 一.信赖域方法 原问题&#xff1a; maxmize J ( θ ) \text{maxmize} \qquad\qquad J(\theta) maxmizeJ(θ) J J J是个很复杂的函数&#xff0c;我们甚至可能不知道 J J J 的解析表达式&#xff…

【Entity Framework】 EF三种开发模式

【Entity Framework】 EF三种开发模式 文章目录 【Entity Framework】 EF三种开发模式一、概述二、DataBase First2.1 DataBase First简介2.2 DataBase First应用步骤2.3 DataBase First总结 三、Model First3.1 Model First简介3.2 Model First实现步骤 四、Code First4.1 Cod…

YOLOv9有效改进专栏汇总|未来更新卷积、主干、检测头注意力机制、特征融合方式等创新![2024/3/23]

​ 专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;助力高效涨点&#xff01;&#xff01;&#xff01; 专栏介绍 YOLOv9作为最新的YOLO系列模型&#xff0c;对于做目标检测的同学是必不可少的。本专栏将针对2024年最新推出的YOLOv9检测模型&#xff0…

一文看懂,如何精细化地进行跨域文件管控

随着企业规模的扩大和分支机构的增多&#xff0c;会出现不同地理位置、组织机构或网络安全域之间进行文件交换的场景。 像很多金融机构在全国或全球范围内会设立不同的分支机构和办事处&#xff0c;因此会存在不同组织机构之间的数据流转&#xff0c;即跨域文件传输。跨域文件传…

知识分享|视频号带货需要满足什么硬性条件?

视频号带货作为一种新兴的电商模式&#xff0c;已经逐渐受到越来越多人的关注。然而&#xff0c;想要在这一领域取得成功&#xff0c;并不是一件轻松的事情。除了需要具备一定的营销技巧和内容创作能力外&#xff0c;还有一些硬性条件必须得到满足。 首先&#xff0c;视频号带货…

GIMP - GNU 图像处理程序 - 中文版

GIMP - GNU 图像处理程序 - 中文版 1. Edit -> Preferences -> Interface2. Chinese [zh_CN]3. 重启 GIMP 即可References 1. Edit -> Preferences -> Interface 2. Chinese [zh_CN] 3. 重启 GIMP 即可 References [1] Yongqiang Cheng, https://yongqiang.blog.…

Xcode Launching “XXX“ is taking longer than expected

文章目录 1.问题2.如何进入iOS DeviceSupport目录3.解决方法4.参考博客 1.问题 LLDB is likely reading from device memory to resolve symbols 2.如何进入iOS DeviceSupport目录 3.解决方法 进入iOS DeviceSupport目录&#xff0c;删除该真机对应的架构文件&#xff08;比如…

谁再问你数据库三范式,这篇文章甩给他!!!

前几天有粉丝私信说面试被问到了数据库三范式&#xff08;面试问这种的不去也好&#xff09;&#xff0c;今天我们就来聊聊。在数据库设计的过程中&#xff0c;为了确保数据的准确性和完整性&#xff0c;我们通常遵循一定的规则和标准&#xff0c;其中最为人所熟知的便是“数据…

C++模版(基础)

目录 C泛型编程思想 C模版 模版介绍 模版使用 函数模版 函数模版基础语法 函数模版原理 函数模版实例化 模版参数匹配规则 类模版 类模版基础语法 C泛型编程思想 泛型编程&#xff1a;编写与类型无关的通用代码&#xff0c;是代码复用的一种手段。 模板是泛型编程…

优化选址问题 | 基于和声搜索算法求解基站选址问题含Matlab源码

目录 问题代码问题 和声搜索算法(Harmony Search, HS)是一种模拟音乐创作过程中乐师们凭借自己的记忆,通过反复调整各乐器的音调,直至达到最美和声状态为启发,通过反复调整解向量的各分量来寻求全局最优解的智能优化算法。 下面是一个基于和声搜索算法求解基站选址问题的…

大创项目推荐 基于图像识别的跌倒检测算法

前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于图像识别的跌倒检测算法 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng-senior/…

MySQL数据库的日志管理以及备份和恢复

目录 1、日志管理 2、查询日志 3、数据备份的重要性 4、数据库备份的分类 4.1物理备份 4.2逻辑备份&#xff1a; 4.3完全备份 5、常见的备份方法 6、MySQL完全备份 6.1MySQL完全备份优缺点 6.2数据库完全备份分类 6.2.1物理冷备份与恢复 6.2.2mysqldump备份…