当前位置: 首页 > news >正文

Dijkstra算法(朴素版堆优化版)

一.写题选哪个版本:

我怎么知道题目是节点少边少、节点少边多、节点多边少、节点多边多呢

这个问题问得非常实际!能问出这个问题,说明你已经完全不满足于“背代码”了

我直接给你一套肉眼判断法,不用分析复杂度,扫一眼题目就能决定用哪个算法。


1、四种情况的判断标准(直接看输入范围)

题目一定会给出数据范围,这就是你的判断依据:

情况V(节点数)E(边数)特点算法选择
节点少边少≤ 500≤ 5000稀疏图堆优化 Dijkstra / 朴素也行
节点少边多≤ 500≈ V²(完全图)稠密图朴素 Dijkstra(O(V²) 最快)
节点多边少10⁴ ~ 10⁵10⁵ ~ 10⁶稀疏图堆优化 Dijkstra(必须)
节点多边多10⁴ ~ 10⁵≈ V²(几乎不可能出现)稠密大图基本不会出现(会爆内存)

2、具体题目对照

题目V 范围E 范围类型推荐算法
743 网络延迟n ≤ 100E ≤ 6000节点少边多(稠密)朴素 Dijkstra
1334 阈值距离n ≤ 100E 可能很多节点少边多朴素 Dijkstra
1631 最小体力m×n ≤ 10⁴≈ 4V(网格图)节点多边少堆优化 Dijkstra
1584 连接点n ≤ 1000完全图(V²/2)节点中等边极多朴素 Prim(稠密)

3、更简单的判断口诀(面试够用)

V 小(≤ 500)→ 无脑朴素
V 大(> 1000)→ 无脑堆优化

为什么?

  • V 小的时候,O(V²) 最多 25 万,堆优化的常数反而吃亏

  • V 大的时候,O(V²) 会爆炸(1 亿+),必须用 O(E log V)

二.dijkstra朴素版

1.基础代码:

package com.Dijkstra; import java.util.Arrays; public class Dijkstra { public static void main(String[] args) { int n=5; int INF=Integer.MAX_VALUE/2; int[][] graph={ {0, 2, INF, 6, INF}, {2, 0, 3, 8, 5}, {INF, 3, 0, INF, 7}, {6, 8, INF, 0, 9}, {INF, 5, 7, 9, 0} }; int start=0; int[] dist=dijkstra(n,graph,start); System.out.println("从0节点到其他所有节点的距离:"); for (int i = 0; i < n; i++) { if(i==start) continue; System.out.println("0->"+i+": "+dist[i]); } } public static int[] dijkstra(int n,int[][] graph,int start){ int[] dist=new int[n]; boolean[] visited=new boolean[n]; int[] parent=new int[n]; //初始化 Arrays.fill(dist,Integer.MAX_VALUE); Arrays.fill(parent,-1); dist[start]=0; for (int i = 0; i < n; i++) { int cur=-1; int min=Integer.MAX_VALUE; //找最小 for (int j = 0; j < n; j++) { if(!visited[j]&&dist[j]<min){ min=dist[j]; cur=j; } } if(cur==-1) break; visited[cur]=true; //更新邻居路径 for (int j = 0; j < n; j++) { if(!visited[j]){ int newDist=dist[cur]+graph[cur][j]; if(newDist<dist[j]){ dist[j]=newDist; parent[j]=cur; } } } } return dist; } }

2.思路:

dist[]存的是七点到该节点的最短路径

visited[]是该节点是否激活(是否被访问过),true是激活,false是未激活

parent[]存的是得到该节点的最短路径的上一个节点,也就是父结点,看是谁使它更新的最短路径

先找最小节点并用cur记录,再更新邻居节点的最短路径

细节:

1.注意是有向图还是无向图,如果是无向图再更新邻居节点的时候就要分类讨论谁作为邻居和cur本身

2.newDist的计算是dist[cur]+该两点之间的路径长度,进行newDist和dist[邻居]比较

三.dijkstra堆优化版

1.基础代码

package com.Dijkstra; import java.util.*; public class DijkstraHeap { /** * Dijkstra 堆优化版(求从 start 到所有点的最短距离) * @param n 节点个数(编号 0 ~ n-1) * @param graph 邻接表,graph[u] = List<int[]{v, w}> 表示 u->v 边权 w * @param start 起点 * @return dist 数组,dist[i] 表示 start 到 i 的最短距离 */ public static int[] dijkstra(int n, List<int[]>[] graph, int start) { // 1. 距离数组,初始化为无穷大 int[] dist = new int[n]; Arrays.fill(dist, Integer.MAX_VALUE); dist[start] = 0; // 2. 优先队列(小顶堆),存 [节点, 当前最短距离] PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[1] - b[1]); pq.offer(new int[]{start, 0}); // 3. 主循环 while (!pq.isEmpty()) { int[] cur = pq.poll(); int u = cur[0]; int d = cur[1]; // 如果队列里的距离比已经记录的远,跳过(重要优化) if (d > dist[u]) continue; // 遍历所有邻居 for (int[] edge : graph[u]) { int v = edge[0]; int w = edge[1]; int newDist = dist[u] + w; if (newDist < dist[v]) { dist[v] = newDist; pq.offer(new int[]{v, newDist}); } } } return dist; } }

2.思路

利用堆每次poll最小的节点,然后更新邻居节点的dist,在更新的同时要进行pq.offer( );

解释:if (d > dist[u]) continue;

在操作的过程中会出现更新的情况,假如说节点2的现在的最短路径是dist[2]=5,然后在往下继续遍历的过程中节点2的最短路径现在是d=10,pq = {2[10], 2[8]},然后根据pq的性质是升序排列的pq就会先弹出的是 2[8],再弹出 2[10],如果不加if (d > dist[u]) continue;让 2[10]直接退出,会造成它会向下错误的改变邻居节点的dist

举例:

修改一点图结构,加一个节点 3:

text

0 → 1 (5) 0 → 2 (10) 1 → 2 (3) 2 → 3 (1)

目标还是 0 → 2(顺便看一下 3 会不会被错误更新)。

正确最短路径:
  • 0 → 1 → 2 → 3
    5 + 3 + 1 =9

如果没有if (d > dist[u]) continue

初始状态:

text

dist = [0, ∞, ∞, ∞] pq = [0[0]]

第 1 步:弹出 [0,0]

  • 更新 [1,5]、[2,10]
    pq = [1[5], 2[10]]

第 2 步:弹出 [1,5]

  • 更新 [2,8]
    pq = [2[8], 2[10]]

第 3 步:弹出 [2,8] ✅

  • 更新 [3,9]
    pq = [2[10], 3[9]]

第 4 步弹出 [2,10]❌ 旧数据

  • 没有continue的话,会执行这一行:
    newDist = dist[2] + 1 = 10 + 1 = 11

  • 比较11 < dist[3] (9)❌ 不成立,不会更新

四.刷题

两种方法都可以写:

743. 网络延迟时间

1334. 阈值距离内邻居最少的城市

只能用堆优化版:

1631. 最小体力消耗路径(因为该题是 节点多n*n 10^4 边少)

1514. 概率最大的路径(节点多边少)

复习:01dx课程🙂

http://www.jsqmd.com/news/795785/

相关文章:

  • 打通企业身份孤岛:Nextcloud无缝对接Active Directory LDAP实战
  • LangGraph Agent 开发指南(1~概述)
  • AD17 3D Body实战:从零绘制异形连接器的简易3D封装
  • 英雄联盟回放播放器终极指南:ROFL-Player完全使用手册
  • 查重全红别慌!2026年5款降AI黑科技亲测,论文降AI轻松降至10%以下 - 降AI实验室
  • 告别软件模拟!用GD32F303的硬件I2C0高效读写EEPROM(附小熊派工程源码)
  • 基于规则引擎与LLM的B站关注列表智能分类实践
  • Day26:角色管理 API 完整教程(CRUD + 分配菜单 + 事务)
  • 如何快速掌握LeagueAkari:面向新手的英雄联盟本地自动化工具完整使用指南
  • STM32新手避坑指南:正点原子、野火、慧净、小马飞控的Systick延时代码到底差在哪?
  • 解锁B站缓存视频:m4s转MP4工具完全指南
  • 报错 SQLite Error 5 database is locked 生产环境怎么排查
  • 小小调度器:轻量任务调度的应用
  • 从 performWorkOnRoot 到 workInProgress tree:React 真正开始 render 的地方
  • C语言指针:从零掌握指针(4)
  • 千问 LeetCode 2227. 加密解密字符串 Python3实现
  • Unitree GO2 ROS2 SDK完整指南:5步实现四足机器人智能控制与自主导航
  • 2026年中石化加油卡回收靠谱平台最新深度测评 - 京顺回收
  • [具身智能-622]:高速图像传感器接口(视觉 / 摄像头)与数据格式
  • 别再只加contentDescription了!Android无障碍适配TalkBack的7个实战避坑点(含完整代码)
  • 根据用户主动关注用户和用户朋友圈以及其他关系层面平台注入的用户 系统推荐程序返回用户推荐列表
  • 第四章 数字孪生制作完整流程
  • 无人机通信安全渗透测试:从信号拦截到GPS欺骗的完整攻防框架
  • 茅台自动预约系统:告别手动抢购,实现智能预约的完整解决方案
  • 从零到精通:手把手教你用BusHound分析SCSI Sense错误码(附完整排查流程)
  • 终极指南:如何通过Typora插件实现高效文件管理与快速切换
  • 洛谷比赛分级
  • 如何用FanControl在5分钟内解决Windows风扇噪音问题?
  • mkcert进阶玩法:一键生成局域网HTTPS证书,让内网测试告别“不安全”警告(含Windows/Linux/Mac多平台指南)
  • WebGLM:基于检索增强生成(RAG)的实时联网智能问答系统实战解析