狄克斯特拉算法

狄克斯特拉算法(Dijkstra’s algorithm)是一种用于在带权图中找到从单一源点到所有其他顶点的最短路径的算法。它适用于处理带有非负权值的图。

下面将详细解释算法的工作原理、时间复杂度以及如何通过优化数据结构来改进其性能。

狄克斯特拉算法的工作原理

  1. 初始化:算法开始时,将所有顶点标记为未访问。源点到自身的距离设为0,其他所有顶点到源点的距离设为无穷大(表示尚未找到路径)。

  2. 选择最小距离顶点:在未访问的顶点中,选择一个具有最小距离的顶点,称为当前顶点。

  3. 松弛操作:对于当前顶点的每一个邻接顶点,执行松弛操作。如果通过当前顶点到邻接顶点的路径比已知的路径更短,则更新该邻接顶点的距离。

  4. 标记访问:将当前顶点标记为已访问,然后从未访问顶点集合中移除。

  5. 重复迭代:重复步骤2到4,直到所有顶点都被访问或者找到目标顶点。

时间复杂度分析

  • 原始算法:在每次迭代中,算法需要从所有未访问的顶点中选择一个最小距离的顶点,这需要 O(n) 的时间。由于有 n 个顶点,因此总的时间复杂度是 O(n^2)。

  • 优化后的算法:通过使用优先队列(如二叉堆或斐波那契堆),算法可以在 O(log n) 的时间内找到最小距离的顶点。更新邻接顶点的距离并将其重新插入优先队列也需要 O(log n) 的时间。因此,对于每个顶点的松弛操作,总时间复杂度是 O(n log n)。由于有 m 条边,每个边可能需要进行一次松弛操作,所以边的松弛操作总时间复杂度是 O(m log n)。综合考虑,优化后的算法时间复杂度是 O((n + m) log n)。

数据结构优化

  • 优先队列:使用优先队列可以快速访问最小元素,并且可以在对数时间内插入和删除元素。这是优化狄克斯特拉算法的关键。

  • 二叉堆:一种常见的实现优先队列的数据结构,但在最坏情况下,插入和删除操作的时间复杂度为 O(log n)。

  • 斐波那契堆:另一种实现优先队列的数据结构,它在平均情况下可以提供更好的性能,特别是在删除最小元素时,平均时间复杂度接近 O(1)。

实际应用中的注意事项

  • 图的表示:图可以以邻接矩阵或邻接表的形式表示。邻接矩阵适用于稠密图,而邻接表适用于稀疏图。

  • 负权边:狄克斯特拉算法不适用于包含负权边的图。对于这种情况,可以使用贝尔曼-福特算法。

  • 算法变体:存在狄克斯特拉算法的变体,如 A* 搜索算法,它使用启发式信息来进一步优化搜索过程。

代码实现

使用数组实现的Dijkstra算法

package mainimport "math"type Graph struct {vertices int     // 图中顶点的数量edges    [][]int // 存储边权重的邻接表
}// NewGraph 创建一个新的图实例
func NewGraph(v int) *Graph {return &Graph{vertices: v,edges:    make([][]int, v),}
}// DijkstraArray 使用数组实现的Dijkstra算法来计算从源顶点到所有其他顶点的最短路径
func (g *Graph) DijkstraArray(src int) []int {dist := make([]int, g.vertices) // 存储从源顶点到每个顶点的最短距离visited := make([]bool, g.vertices) // 记录顶点是否已经被访问过// 初始化距离数组,所有顶点距离设为无穷大for i := range dist {dist[i] = math.MaxInt32}dist[src] = 0 // 源顶点到自身的距离设为0// 找到最短距离的顶点进行迭代更新for count := 0; count < g.vertices-1; count++ {u := g.minDistance(dist, visited) // 从未访问过的顶点中找到距离最小的顶点visited[u] = true // 标记顶点u为已访问// 更新顶点u的邻接顶点的最短距离for v := 0; v < g.vertices; v++ {if !visited[v] && g.edges[u][v] != 0 && dist[u]+g.edges[u][v] < dist[v] {dist[v] = dist[u] + g.edges[u][v]}}}return dist // 返回从源顶点到所有其他顶点的最短距离数组
}// minDistance 辅助函数,找到当前距离数组中距离最小的顶点
func (g *Graph) minDistance(dist []int, visited []bool) int {min := math.MaxInt32minIndex := -1for v := range dist {if !visited[v] && dist[v] <= min {min = dist[v]minIndex = v}}return minIndex
}func main() {g := NewGraph(9)g.edges = [][]int{{0, 4, 0, 0, 0, 0, 0, 8, 0},{4, 0, 8, 0, 0, 0, 0, 11, 0},{0, 8, 0, 7, 0, 4, 0, 0, 2},{0, 0, 7, 0, 9, 14, 0, 0, 0},{0, 0, 0, 9, 0, 10, 0, 0, 0},{0, 0, 4, 14, 10, 0, 2, 0, 0},{0, 0, 0, 0, 0, 2, 0, 1, 6},{8, 11, 0, 0, 0, 0, 1, 0, 7},{0, 0, 2, 0, 0, 0, 6, 7, 0},}distances := g.DijkstraArray(0)println("Shortest distances from source vertex 0:")for i, dist := range distances {println(i, ":", dist)}
}

使用最小堆实现优先级队列的Dijkstra算法

package main  import (  "container/heap"  "fmt"  "math"  
)  // Item 是优先级队列中的元素,包含顶点和其距离  
type Item struct {  vertex int // 顶点  dist   int // 顶点的当前距离  index  int // 顶点在dist数组中的索引(可选,用于更新)  
}  // PriorityQueue 是优先级队列,基于Item的dist字段排序  
type PriorityQueue []*Item  func (pq PriorityQueue) Len() int { return len(pq) }  func (pq PriorityQueue) Less(i, j int) bool {  return pq[i].dist < pq[j].dist  
}  func (pq PriorityQueue) Swap(i, j int) {  pq[i], pq[j] = pq[j], pq[i]  pq[i].index = i  pq[j].index = j  
}  func (pq *PriorityQueue) Push(x interface{}) {  n := len(*pq)  item := x.(*Item)  item.index = n  *pq = append(*pq, item)  
}  func (pq *PriorityQueue) Pop() interface{} {  old := *pq  n := len(old)  item := old[n-1]  item.index = -1 // for safety  *pq = old[0 : n-1]  return item  
}  func (pq *PriorityQueue) update(item *Item, dist int) {  item.dist = dist  heap.Fix(pq, item.index)  
}  // Edge 表示图中的一条边  
type Edge struct {  to     int // 目标顶点  weight int // 边的权重  
}  // Graph 表示整个图结构  
type Graph struct {  vertices int       // 图中顶点的数量  edges    [][]*Edge // 存储边的邻接表,使用指针避免复制  
}  // DijkstraMinHeap 使用最小堆优先级队列的Dijkstra算法  
func (g *Graph) DijkstraMinHeap(src int) []int {  dist := make([]int, g.vertices)  for i := range dist {  dist[i] = math.MaxInt32  }  dist[src] = 0  pq := make(PriorityQueue, 0)  heap.Init(&pq)  heap.Push(&pq, &Item{vertex: src, dist: 0})  for pq.Len() > 0 {  item := heap.Pop(&pq).(*Item)  u := item.vertex  for _, edge := range g.edges[u] {  v := edge.to  alt := dist[u] + edge.weight  if alt < dist[v] {  dist[v] = alt  heap.Push(&pq, &Item{vertex: v, dist: alt})  }  }  }  return dist  
}  func main() {  // 初始化图的边的连接关系  graph := Graph{  vertices: 9,  edges: [][]*Edge{  {{to: 1, weight: 4}, {to: 7, weight: 8}},  {{to: 0, weight: 4}, {to: 2, weight: 8}, {to: 7, weight: 11}},  {{to: 1, weight: 8}, {to: 3, weight: 7}, {to: 5, weight: 4}, {to: 8, weight: 2}},  {{to: 2, weight: 7}, {to: 4, weight: 9}, {to: 5, weight: 14}},  {{to: 3, weight: 9}, {to: 5, weight: 10}},  {{to: 2, weight: 4}, {to: 3, weight: 14}, {to: 4, weight: 10}, {to: 6, weight: 2}}, {{to: 5, weight: 2}, {to: 7, weight: 1}, {to: 8, weight: 6}},  {{to: 0, weight: 8}, {to: 1, weight: 11}, {to: 6, weight: 1}, {to: 8, weight: 7}},  {{to: 2, weight: 2}, {to: 6, weight: 6}, {to: 7, weight: 7}}, },  }  distances := graph.DijkstraMinHeap(0)fmt.Println("Shortest distances from source vertex 0:")for i, dist := range distances {fmt.Printf("%d: %d\n", i, dist)}
}

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

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

相关文章

复制 pdf 的表格到 markdown 版本的Typora 或者 word 中

在 pdf 中选中复制表格内容&#xff0c;直接粘贴到 typora 中失败&#xff0c;可以使用 txt文件和 excel 做过渡。 准备一个空的 txt 文件&#xff0c;将 pdf 中表格的数据复制粘贴到txt文件中&#xff0c;文本内容会以空格分开&#xff0c;如下图的形式&#xff1a; 打开 exc…

Android Gradle 开发与应用-Gradle基础

Gradle 是一个基于 Groovy 和 Kotlin DSL&#xff08;领域特定语言&#xff09;的构建自动化工具&#xff0c;特别适合用于大型项目的自动化构建。它广泛用于 Android 开发&#xff0c;因为它的灵活性和强大的依赖管理能力。下面是 Gradle 的基础介绍&#xff0c;特别是针对 An…

firewalld防火墙转发流量到其他端口forward port rules

假设云主机eth0: 47.93.27.106 tun0: inet 10.8.0.1 netmask 255.255.255.0 Show rules for a specific zone (public) sudo firewall-cmd --zonepublic --list-all Add the tun0 interface to the public zone: sudo firewall-cmd --zonepublic --add-interfacetun0 --…

手把手教你考下39张免费亚马逊AWS证书和学习徽章

小李哥目前共考了39项亚马逊云(AWS)徽章&#xff0c;这也是普通用户可考的全部徽章。这篇文章会介绍如何报名、复习、通过这39张徽章提升云计算基本技能&#xff0c;了解全球第一大云厂亚马逊云科技前沿技术。这篇文章在领英爆&#x1f525;&#xff0c;有将近100k浏览量和11k的…

MeterSphere v3.0全新启航,让软件测试工作更简单、更高效

2024年7月1日&#xff0c;MeterSphere v3.0版本正式发布。MeterSphere v3.0是新一代的测试管理和接口测试工具&#xff0c;致力于让软件测试工作更简单、更高效&#xff0c;不再成为持续交付的瓶颈。 在团队协作方面&#xff0c;针对目前企业软件测试团队所面临的测试工具不统…

Java中使用KMP算法解决力扣459.重复的子字符串问题

在解决字符串相关问题时&#xff0c;KMP&#xff08;Knuth-Morris-Pratt&#xff09;算法是一个非常有用的工具。今天&#xff0c;我们将使用KMP算法来解决力扣&#xff08;LeetCode&#xff09;上的一个经典问题&#xff1a;459. 重复的子字符串。 力扣459.重复的子字符串 题…

终止线程的典型方式

终止线程一般不使用JDK提供的 stop()/destory() 方法它们本身也被JDK废弃了。通常的做法是提供一个boolean型的终止变量&#xff0c;当这个变量置为false&#xff0c;则终止线程的运行。 public class stopThread implements Runnable {private boolean flag true;Overridepu…

数据安全与隐私保护在返利App中的实施策略

数据安全与隐私保护在返利App中的实施策略 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 一、引言 随着移动互联网的发展&#xff0c;返利App作为一种流行的…

深度学习项目GPU开发环境安装

注安装环境&#xff1a;ubuntu22.04, cuda 11.7, cudnn8.9 1.安装nvidia驱动 看可安装的Nvidia驱动版本&#xff1a;执行 ubuntu-drivers devices 安装合适版本的Nvidia驱动&#xff1a; sudo apt-get install nvidia-driver-515 注意&#xff1a;合适的版本需要尝试&#x…

5.12 Firmware Image Download command

5.12 Firmware Image Download command Firmware Image Download命令用于下载全部或部分image&#xff0c;以便将来更新控制器。当Admin Submission Queue 或 I/O Submission Queues 上的其他命令未完成时&#xff0c;可能会提交Firmware Image Download命令。Firmware Image …

从0开始建SMARTFORMS表格

一、简介步骤 1、设置纸张的大小&#xff08;页格式&#xff09; 2、设置字体大小&#xff08;样式&#xff09; 3、设置表格模板 二、详细操作步骤 1、设置页格式 事务码&#xff1a;SPAD 参考操作&#xff1a;SAP Smartforms页格式创建与使用_sap 页格式-CSDN博客 SA…

websocket (@ServerEndpoint)基本使用指南

概述 websocket 介绍 WebSocket 是一种通信协议&#xff0c;通过单个 TCP 连接提供全双工通信通道。它允许客户端和服务器之间进行双向通信、实时交互&#xff0c;比如在线聊天、实时数据展示等。 与传统的 HTTP 协议不同&#xff0c;WebSocket 连接是持久的&#xff0c;可以在…

godis源码分析——TCP服务

前言 Godis 是一个用 Go 语言实现的 Redis 服务器。 地址&#xff1a;https://github.com/HDT3213/godis?tabreadme-ov-file 简单架构描述 godis是一个中心服务&#xff0c;是TCP服务。流程大概是&#xff1a;godis开启服务&#xff0c;客户端通过TCP建立连接。客户端发起…

【网络安全】修改Host文件实现域名解析

场景 开发一个网站或者服务&#xff0c;需要在本地测试时&#xff0c;可以将线上的域名指向本地开发环境的IP地址。从而模拟真实环境中的域名访问&#xff0c;方便调试和开发。 步骤 1、以管理员身份打开命令提示符 2、编辑hosts文件&#xff1a; 输入以下命令打开hosts文…

Suno: AI音乐创作的新时代

名人说:一点浩然气,千里快哉风。 ——苏轼 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 一、什么是Suno?1、Suno2、应用场景二、如何使用Suno制作音乐?步骤1:注册并登录Suno平台步骤2:创建音乐项目步骤3:生成音乐片段三、Suno的影响很高兴你打开了…

【第六节】C/C++静态查找算法

目录 前言 一、搜索查找 二、查找算法 1. 线性查找&#xff08;Linear Search&#xff09; 2. 二分查找&#xff08;Binary Search&#xff09; 3. 插值查找&#xff08;Interpolation Search&#xff09; 4. 哈希查找&#xff08;Hash Search&#xff09; 5. Fibonacc…

C++感受12-Hello Object 派生版

不变的功能&#xff0c;希望直接复用原有代码&#xff1b;变化的功能&#xff0c;希望在分开的代码里实现。 派生的基本概念和目的如何定义派生类以及创建派生对象派生对象的生死过程 0. 课堂视频 ff14-HelloObject-派生版 1. 派生的基本概念与目的 编程&#xff0c;或者说软…

python 音频和视频合并自动裁剪

为了将音频和视频合并并自动裁剪&#xff0c;我们可以使用Python中的moviepy库。moviepy是一个强大的视频处理库&#xff0c;它允许我们进行剪辑、裁剪、合并等操作。 以下是一个详细的步骤和代码示例&#xff0c;说明如何使用moviepy来合并音频和视频&#xff0c;并自动裁剪它…

vue中的坑·

常规 1.使用watch时&#xff0c;immediate true会在dom挂载前执行 2.使用this.$attrs和props 可以获取上层非原生属性&#xff08;class/id&#xff09; 多层次嵌套引用 设置的时候直接赋值&#xff0c;修改的时候即使用的双向绑定加上$set / nextick / fouceUpdate都不会同步…

FastGPT 错误:Embedding API is not responding

一、FastGPT 报错 在调用 Embedding 模型对文档切片向量化的时候 FastGPT 出现如下错误。 [Error] 2024-07-01 08:41:00 Embedding API is not responding {message: <!doctype html><html lang="zh-CN"><head><meta charset="utf-8&qu…