狄克斯特拉算法

狄克斯特拉算法(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 main

import "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.MaxInt32
	minIndex := -1

	for 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.mfbz.cn/a/760947.html

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

相关文章

开源视频配音技术

FoleyCrafter 是一个基于文本的视频配音技术&#xff0c;能够生成与输入视频在语义上相关且时间上同步的高质量音频, 可以在 HF 上免费使用。

华为智能驾驶方案剖析

华为ADS智驾方案始终坚持激光雷达毫米波雷达摄像头的多传感器融合路线&#xff0c;行业降本压力下硬件配置从超配逐步转向贴合实际需求&#xff0c;带动整体硬件成本下降。 1)单车传感器数量呈现下降趋势&#xff0c;包括激光雷达从3个减配至1个、毫米波雷达从6R减配至3R、摄像…

JsonCpp:更简洁的序列化及反序列化

简介 jsoncpp 提供了一组简单易用的 API&#xff0c;使得在 C 程序中处理 JSON 数据变得更加方便和高效。 安装 linux环境下安装jsoncpp sudo apt-get update sudo apt-get install --reinstall libjsoncpp-dev建立软链接确保编译器找到头文件 #include <json/json.h>…

PC系统安装引导:2、进入维护环境

目录 &#x1f345;点击这里查看所有博文 闲来无事&#xff0c;记录下自己以往多年总结出的一套系统维护的方法。以供有需要的人学习使用。例如&#xff0c;系统崩溃了无法启动怎么办&#xff0c;如何重做系统&#xff0c;如何安装双系统&#xff0c;如何引导多系统&#xff0…

F_SETFL的例子

代码; #include <unistd.h> #include <fcntl.h> #include <stdio.h> #include <string.h>int main(void) {int flags-1;char buf[]"FCNTL";int fdopen("test.txt",O_RDWR);flagsfcntl(fd,F_GETFL,0);flags|O_APPEND;flagsfcntl(f…

如何完成域名解析验证

一&#xff1a;什么是DNS解析&#xff1a; DNS解析是互联网上将人类可读的域名&#xff08;如www.example.com&#xff09;转换为计算机可识别的IP地址&#xff08;如192.0.2.1&#xff09;的过程&#xff0c;大致遵循以下步骤&#xff1a; 查询本地缓存&#xff1a;当用户尝…

Python28-4 KNN近邻算法

KNN&#xff08;K-Nearest Neighbors&#xff09;算法是一种常用的机器学习算法&#xff0c;主要用于分类和回归问题。 1. KNN算法的基本概念 KNN算法是一种基于实例的学习算法&#xff0c;也称为惰性学习&#xff08;Lazy Learning&#xff09;算法&#xff0c;因为它在训练…

快递物流仓库管理系统java项目springboot和vue的前后端分离系统java课程设计java毕业设计

文章目录 快递物流仓库管理系统一、项目演示二、项目介绍三、部分功能截图四、部分代码展示五、底部获取项目源码&#xff08;9.9&#xffe5;带走&#xff09; 快递物流仓库管理系统 一、项目演示 快递物流仓库管理系统 二、项目介绍 语言: Java 数据库&#xff1a;MySQL 前…

苹果手机图片识别文字出现日期?这里教你如何调整

一、问题原因分析 首先&#xff0c;我们需要理解为什么会出现这种情况。通常&#xff0c;苹果手机在识别图片中的文字时&#xff0c;会根据图片的内容和上下文来显示相关信息。如果图片中包含明显的日期信息&#xff0c;或者手机的某些设置将图片识别与日期显示相关联&#xf…

MicroBin好用的粘贴板工具

有时候你可能想从一台电脑上粘贴文本到另一台电脑上&#xff0c;或者是你想要分享一张图片或者是一些文件&#xff0c;某些设备上登陆qq和微信有不太方便&#xff0c;那么就可以使用MicroBin&#xff0c;它不但可以实现跨设备复制粘贴的功能&#xff0c;还支持文件上传等功能 …

Games101学习笔记 Lecture 14: Ray Tracing 2 (Acceleration Radiometry)

Lecture 14: Ray Tracing 2 (Acceleration & Radiometry 一、加速光线追踪 AABB1.均匀网格 Uniform Spatial Partitions (Grids)①前处理-构建加速网格②射线与场景相交③网格分辨率④适用情况 2.空间划分KD-Tree①预处理②数据结构③遍历④问题 3.对象划分 & 包围盒层…

表单外链,支持查看方式设置

06/19 主要更新模块概览 外链设置 跳转缩放 打印调整 数据校验 01 表单管理 1.1 【表单外链】-填写外链新增查看方式设置 说明&#xff1a; 原表单填写外链&#xff0c;填写字段权限和查看权限统一字段设置&#xff0c;用户在填写时看到数据与查看数据一致…

Python | 基于支持向量机(SVM)的图像分类案例

支持向量机&#xff08;SVM&#xff09;是一种监督机器学习算法&#xff0c;可用于分类和回归任务。在本文中&#xff0c;我们将重点关注使用SVM进行图像分类。 当计算机处理图像时&#xff0c;它将其视为二维像素阵列。数组的大小对应于图像的分辨率&#xff0c;例如&#xf…

常用图片处理操作

静态图片文件转base64 import base64 with open(1.png, rb) as f:source f.read() base64_img base64.b64encode(source)base64转静态图片文件 imgdata base64.b64decode(base64_img)# 将图片保存为文件 with open("new.png", wb) as f:f.write(imgdata)PS:这里…

精密空气加热器负载组

小型便携式 &#xff1a;精密空气加热器&#xff08;负载组&#xff09;能够对数据中心热通道/冷通道冷却系统进行全面测试。EAK 是一款 19 英寸机架式设备&#xff08;10U 高&#xff09;&#xff0c;可轻松安装到各种标准服务器机架中。通过集成可调节的热量水平&#xff08;…

【计算机毕业设计】061互助学习微信小程序

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

Redis学习——Redisson 分布式锁集成及其简单使用

文章目录 引言1. Redisson概述1.1 Redisson的基本概念1.2 Redisson的主要功能1.3 Redisson的优点 2. 开发环境3. Redisson的安装与配置3.1 添加依赖3.2 配置Redisson 4. 使用Redisson4.1 可重入锁4.1.1 可重入锁的概念4.1.2 可重入锁的实现原理4.1.3 简单使用锁的获取和释放 4.…

无线麦克风哪个品牌音质最好,一篇看懂无线领夹麦克风怎么挑选

在数字化时代背景下&#xff0c;直播和个人视频日志&#xff08;Vlog&#xff09;已成为新的文化现象&#xff0c;这些趋势不仅重塑了内容创作&#xff0c;也促进了音频设备市场的繁荣。无线领夹麦克风&#xff0c;以其设计上的轻便和录音上的高效率&#xff0c;成为视频创作者…

手把手带你薅一台云服务器

前两篇&#xff0c;带着大家在自己本地搞了一台 Linux 虚拟机&#xff1a; 【保姆级教程】Windows上安装Linux子系统&#xff0c;搞台虚拟机玩玩【保姆级教程】Windows 远程登陆 Linux 服务器的两种方式&#xff1a;SSH VS Code&#xff0c;开发必备 问题来了&#xff1a;本…

nacos漏洞小结

Alibaba Nacos是阿里巴巴推出来的一个新开源项目&#xff0c;是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。致力于帮助发现、配置和管理微服务。Nacos提供了一组简单易用的特性集&#xff0c;可以快速实现动态服务发现、服务配置、服务元数据及流量管理…