最短路径算法——dijkstra

article/2025/8/25 2:53:58

dijkstra

前提:在一张图里,不能有权值为负数的边

给你一个出发点,求出发点到所有结点的最短距离是多少?如果无法到达某个点,则到这个点的距离是正无穷(一般出现在有向图里面)。

举个,例子,看如下图:右边集合表示的是A点到集合中各个点的最短距离。

在这里插入图片描述
一开始,假设A点到所有其它点的距离是正无穷,就是假设都不可到达:

在这里插入图片描述
A作为一个桥连点出现后,A到B点的距离就是原先A到A(0)的距离加上A到B的距离(1),后面的类似,所以得到如下图:

在这里插入图片描述
当A这个点的记录使用完了之后,就永远不去改动它,就是上图中圈起来的A点。然后在剩下的记录中选一个最小的记录;B点对应1,意思就是从原点出发到达B的距离是1,再以B作为桥连点往外找。发现B到C的距离为2,B到E的距离为170,所以可以更新表中C点的记录为3(AB+BC),E的记录更新为171(AB+BE)。之后B点这条记录也永远不去改动。在表中使用了哪条记录就将其锁住,再也不碰它。

在这里插入图片描述
接下来,就是C点。。。同样的逻辑玩下去。最终表里全部锁死的记录就是dijkstra要求的记录。

在这里插入图片描述
注意,中间如果碰到距离相同的可以不更新。这好像有点贪心思想啊。

但问题是如何在表里找最小的记录呢,可以每次遍历来找,但是有点麻烦。所以更好的方式是利用小根堆。

小根堆会自动组织好,每次把最小的值弹出来,但在这里我们还有一个要求,就是我们有可能要更改已经在堆里组织好的值,这样的话,系统提供的堆实现不了。我们需要手动改写堆!推荐看看这两篇文章——系统提供的堆 VS 手动改写堆 & 堆排序,,。可以更好理解dijkstra算法的改进。

然后我们依次来看自己手写的小根堆要实现的功能有哪些,

1)add(),添加一条记录的方法,就是从原点到某个点的距离是多少,并且按距离来组织

2)update(),更新的方法,需要更新某条记录的距离。比如原点到X点的距离是100,但是通过某个桥连点到X的距离是20了,所以这条记录的距离就要更新成20,并且这条记录要在小根堆里往上heapInsert(),自动组织好顺序

3)ignore(),忽略点某个已经使用过的结点的方法。

小根堆里装的东西的结构就是:

public static class NodeRecord {public Node node;public int distance;public NodeRecord(Node node, int distance) {this.node = node;this.distance = distance;}}

以下代码分别实现了dijkstra算法的两种方法

package com.harrison.class11;import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;import com.harrison.class11.Code01_NodeEdgeGraph.*;public class Code07_dijkstra {// 从from点到key的最短距离是valuepublic static HashMap<Node, Integer> dijkstra1(Node from) {HashMap<Node, Integer> distanceMap = new HashMap<>();distanceMap.put(from, 0);// 一开始,自己到自己的距离当然是0// 锁住已经使用过的记录HashSet<Node> selectedNodes = new HashSet<>();Node minNode=getMinDistanceNodeAndUnselectedNode(distanceMap, selectedNodes);while(minNode!=null) {int distance=distanceMap.get(minNode);for(Edge edge:minNode.edges) {Node toNode=edge.to;if(!distanceMap.containsKey(toNode)) {distanceMap.put(toNode, distance+edge.weight);}else {distanceMap.put(edge.to, Math.min(distanceMap.get(toNode), distance+edge.weight));}}selectedNodes.add(minNode);minNode=getMinDistanceNodeAndUnselectedNode(distanceMap, selectedNodes);}return distanceMap;}// 在distanceMap表里面排除掉在selectedNodes集合的点,然后选则距离最小的点返回public static Node getMinDistanceNodeAndUnselectedNode(HashMap<Node, Integer> distanceMap,HashSet<Node> selectedNodes) {Node minNode = null;int minDistance = Integer.MAX_VALUE;// EntrySet可以遍历HashMap中的值for(Entry<Node, Integer> entry:distanceMap.entrySet()) {Node node=entry.getKey();int distance=entry.getValue();if(!selectedNodes.contains(node) && distance<minDistance) {minNode=node;minDistance=distance;}}return minNode;}public static class NodeRecord{public Node node;public int distance;public NodeRecord(Node n,int d) {node=n;distance=d;}}public static class NodeHeap{// 实际的堆结构private Node[] nodes;// key在堆中的位置就是value// 如果value是-1代表这个结点曾经进过堆(进来之后弹出了)private HashMap<Node, Integer> heapIndexMap;// 源结点到key的最小距离就是valueprivate HashMap<Node, Integer> distanceMap;private int size;// 堆上有多少个点public NodeHeap(int size) {nodes=new Node[size];heapIndexMap=new HashMap<>();distanceMap=new HashMap<>();this.size=0;}public boolean isEmpty() {return size==0;}// 如果某个结点在heapIndexMap表有记录,表示曾经进过堆public Boolean isEntered(Node node) {return heapIndexMap.containsKey(node);}public boolean inHeap(Node node) {return isEntered(node) && heapIndexMap.get(node)!=-1;}public void heapInsert(Node node,int index) {while(distanceMap.get(nodes[index])<distanceMap.get(nodes[(index-1)/2])) {swap(index, (index-1)/2);index=(index-1)/2;}}public void heapfiy(int index,int size) {int left=2*index+1;while(left<size) {int smallest=(left+1<size) &&(distanceMap.get(nodes[left+1])<distanceMap.get(nodes[left]))?left+1:left;smallest=distanceMap.get(nodes[smallest])<distanceMap.get(nodes[index])?smallest:index;if(smallest==index) {break;}swap(smallest, index);index=smallest;left=2*index+1;}}private void swap (int index1,int index2) {heapIndexMap.put(nodes[index1], index2);heapIndexMap.put(nodes[index2], index1);Node tmp=nodes[index1];nodes[index1]=nodes[index2];nodes[index2]=tmp;}// 有一个点node,如果发现了一个从源节点到node的距离为distance// 判断要不要更新,如果需要更新,就更新public void addOrUpdateOrIgnore(Node node,int distance) {if(inHeap(node)) {// 如果结点在堆上,有可能更新完记录后,距离变小,所以需要调整堆distanceMap.put(node, Math.min(distanceMap.get(node), distance));heapInsert(node, heapIndexMap.get(node));}if(!isEntered(node)){// 如果没有进过堆,那么将这个结点挂在堆的最后一个结点nodes[size]=node;// 这个结点的位置就在heapIndexMap表的size位置上heapIndexMap.put(node, size);distanceMap.put(node, distance);heapInsert(node, size++);}// 如果两个if都没中,说明这个结点既不在堆上,但是又进来过,// 相当于什么都没做就直接返回}public NodeRecord pop(){NodeRecord nodeRecord=new NodeRecord(nodes[0], distanceMap.get(nodes[0]));swap(0, size-1);// 堆顶弹出后,标记为-1,并移除相应的距离记录heapIndexMap.put(nodes[size-1], -1);distanceMap.remove(nodes[size-1]);// 释放size-1位置上的东西nodes[size-1]=null;heapfiy(0, --size);return nodeRecord;}}// 改进后的dijkstra算法// 从head出发,所有head能到达的结点// 生成到达每个结点的最小路径记录并返回public static HashMap<Node, Integer> dijkstra2(Node head,int size){NodeHeap nodeHeap=new NodeHeap(size);nodeHeap.addOrUpdateOrIgnore(head, 0);HashMap<Node, Integer> ans=new HashMap<>();while(!nodeHeap.isEmpty()) {NodeRecord recored=nodeHeap.pop();Node cur=recored.node;int distance=recored.distance;for(Edge edge:cur.edges) {nodeHeap.addOrUpdateOrIgnore(edge.to, edge.weight+distance);}ans.put(cur, distance);}return ans;}
}

http://chatgpt.dhexx.cn/article/2F17HPTf.shtml

相关文章

最短路径算法详解

前言&#xff1a; 最短路径算法&#xff1a;用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展&#xff0c;直到扩展到终点为止。 例子&#xff1a; 暑期&#xff0c;你想要出门去旅游&#xff0c;但是在你出发之前&#xff0c;你想知道任意…

基于java最短路径算法的简单实现

一、我们先画一个可达路径图表&#xff1a; -1表示不可直达&#xff0c;0表示自己&#xff0c;其他整数表示长度或者权重 ABCDA012-1B-1015C-1-101D-1-1-10 用图形可表示为&#xff1a; 二、算法思路 1、先列出所有保存所有节点到可达节点的路径二维表 2、逐步寻找从起始节点到…

最短路径算法及应用

乘汽车旅行的人总希望找出到目的地的尽可能的短的行程。如果有一张地图并在图上标出每对十字路口之间的距离&#xff0c;如何找出这一最短行程&#xff1f;  一种可能的方法就是枚举出所有路径&#xff0c;并计算出每条路径的长度&#xff0c;然后选择最短的一条。那么我们很…

关于最短路径算法的理解

“最短路径算法:Dijkstra算法&#xff0c;Bellman-Ford算法&#xff0c;Floyd算法和SPFA算法等。​从某顶点出发&#xff0c;沿图的边到达另一顶点所经过的路径中&#xff0c;各边上权值之和最小的一条路径叫做最短路径。” 我们解决最短路径问题&#xff0c;常用的是Dijkstra…

最短路径算法-----Dijkstra迪杰斯特拉算法

最近巩固一下算法&#xff0c;提高自己内力&#xff0c;网上看到查看到这篇介绍很详细的《Dijkstra迪杰斯特拉算法》&#xff0c;在这里转载记录一下。 1 前言 本章介绍迪杰斯特拉算法。和以往一样&#xff0c;本文会先对迪杰斯特拉算法的理论论知识进行介绍&#xff0c;然后给…

Dijkstra 最短路径算法 Python 实现

原文链接 问题描述 使用 Dijkstra 算法求图中的任意顶点到其它顶点的最短路径&#xff08;求出需要经过那些点以及最短距离&#xff09;。 以下图为例&#xff1a; 算法思想 可以使用二维数组来存储顶点之间边的关系 首先需要用一个一维数组 dis 来存储 初始顶点到其余各个顶…

神经网络最短路径算法,最短路径算法的原理

节约里程法求解最短路问题 你只要记住2点之间直线最短。节约里程法是用来解决运输车辆数目不确定的问题的最有名的启发式算法。1、节约里程法优化过程分为并行方式和串行方式两种。 核心思想是依次将运输问题中的两个回路合并为一个回路&#xff0c;每次使合并后的总运输距离…

最短路径算法及Python实现

最短路径问题 在图论中&#xff0c;最短路径问题是指在一个有向或无向的加权图中找到从一个起点到一个终点的最短路径。这个问题是计算机科学中的一个经典问题&#xff0c;也是许多实际问题的基础&#xff0c;例如路线规划、通信网络设计和交通流量优化等。在这个问题中&#…

图论:图的四种最短路径算法

目录&#xff1a; 1.DFS&#xff08;单源最短路径算法&#xff09; 例题1&#xff1a; DFS题目分析&#xff1a; 代码DFS&#xff1a; 2.Floyed&#xff08;时间复杂度On^3&#xff09; 1.应用场景&#xff1a; 2.解析算法&#xff1a; 核心代码1&#xff1a; 我的笔…

图的五种最短路径算法

本文总结了图的几种最短路径算法的实现:深度或广度优先搜索算法,费罗伊德算法,迪杰斯特拉算法,Bellman-Ford 算法。 1)深度或广度优先搜索算法(解决单源最短路径) 从起点开始访问所有深度遍历路径或广度优先路径,则到达终点节点的路径有多条,取其中路径权值最短的一…

最短路径算法——Dijkstra算法——python3实现

本文参考来自数据结构与算法分析 java语言描述。 文章目录 问题描述问题分析实现过程如何使用数据变化表代码实现优先队列中的堆排序使用set代替优先队列得到最短路径 负权边算法改进&#xff08;若为无圈图&#xff09; 问题描述 现有一个有向赋权图。如下图所示&#xff1a;…

最短路径算法的编程与实现 C语言

一 、目的&#xff1a; 1.掌握最短路径算法的基本原理及编程实现&#xff1b; 二 、环境&#xff1a; operating system version&#xff1a;Win11 CPU instruction set: x64 Integrated Development Environment&#xff1a;Viusal Studio 2022 三 、内容&#xff1a; 1…

图的四种最短路径算法

本文总结了图的几种最短路径算法的实现&#xff1a;深度或广度优先搜索算法&#xff0c;弗洛伊德算法&#xff0c;迪杰斯特拉算法&#xff0c;Bellman-Ford算法 1&#xff09;&#xff0c;深度或广度优先搜索算法&#xff08;解决单源最短路径&#xff09; 从起始结点开始访问所…

算法之几个常见的经典最短路径算法

目录 1. Dijkstra算法2. Floyd算法3. Bellman-Ford 算法 1. Dijkstra算法 是解单源最短路径问题的贪心算法。 有一向带权图 G (V, E)&#xff0c;包含右n个顶点&#xff0c;其中每条边的权是非负实数&#xff0c;定义数组 dist 为原点到G中各个顶点的距离&#xff0c;初始化为…

最短路径的四种算法

最短路径四种算法 1234FloydDijkstraBellman-Ford队列优化的Bellman-Ford 一&#xff0c;只有四行的算法——Floyd-Warshall 假设求顶点 V i Vi Vi到 V j Vj Vj的最短路径。弗洛伊德算法依次找从 V i Vi Vi到 V j Vj Vj&#xff0c;中间经过结点序号不大于 0 0 0的最短路径&…

最短路径算法

1.最短路径算法分为单源最短路径算法和多源最短路径算法 &#xff08;a&#xff09;单源最短路径算法&#xff0c;可以计算出从起点到任意一个起点的最短路径。 例如&#xff1a;Dijkstra算法 &#xff0c;SPFA算法 &#xff08;b&#xff09;多源最短路径算法&#xff0c;可…

哈夫曼树及其应用

1、哈夫曼树的基本概念 ---- 哈夫曼&#xff08;Huffman&#xff09;树又称作最优二叉树&#xff0c;它是n个带权叶子结点构成的所有二叉树中&#xff0c;带权路径长度最小的二叉树。 ---- “路径”就是从树中的一个结点到另一个结点之间的分支构成的部分&#xff0c;而分支…

哈夫曼树的C语言实现

什么是哈夫曼树 当用 n 个结点&#xff08;都做叶子结点且都有各自的权值&#xff09;试图构建一棵树时&#xff0c;如果构建的这棵树的带权路径长度最小&#xff0c;称这棵树为“最优二叉树”&#xff0c;有时也叫“赫夫曼树”或者“哈夫曼树”。 在构建哈弗曼树时&#xff0…

哈夫曼树的构建及编码

哈夫曼树的构建及编码 文章目录 哈夫曼树的构建及编码一、什么是哈夫曼树二、什么是哈夫曼编码三、怎么建哈夫曼树、求哈夫曼编码四、为什么哈夫曼编码能实现压缩 声明&#xff1a;关于文件压缩&#xff0c;不是本文的重点&#xff0c;本文只说明并讨论哈夫曼树的构建和编码&am…

如何构建一棵哈夫曼树

给一个数列{10,7,8,3,26,5,1},要求转成为一棵哈夫曼树。 分析思路以及图解&#xff1a; 第一步&#xff1a;将数列进行排序&#xff0c;按从小到大的顺序。最终结果为{1,3,5,7,8,10,26}&#xff0c;根据每个数值创建结点&#xff0c;组成结点数组 第二步&#xff1a;取出权值最…