使用rust学习基本算法(一)

文章目录

  • 使用rust学习基本算法(一)
    • 实现思路拆解:
    • 完整代码:
      • 测试
    • Dijkstra算法的特点
    • 应用场景
    • 学习Dijkstra算法的建议
    • 学习Dijkstra算法的建议

使用rust学习基本算法(一)

Dijkstra算法是一种著名的算法,用于在加权图中找到最短路径。它由荷兰计算机科学家艾兹格·戴克斯特拉(Edsger W. Dijkstra)于1956年提出,并且在1959年发表。这个算法可以找到从图中一个指定的源节点到所有其他节点的最短路径。它能够处理有向和无向图,但前提是图中的边权重不能为负数。

Dijkstra算法的核心思想是贪心算法。

[!NOTE]

贪心算法

贪心算法是一种在每一步选择中都采取当前状态下最优的选择,从而希望导致结果是全局最优的算法策略。这种算法在解决某些优化问题时非常有效,尤其是当局部最优选择能够确保找到全局最优解的问题中。贪心算法的关键是,它做出选择时,仅考虑当前状态,不考虑结果将如何影响未来的选择。

贪心算法的特点:

  • 局部最优选择:在每一步都做出当前看来最好的选择。
  • 无回溯:一旦做出选择,就不再改变。
  • 简单高效:通常情况下,贪心算法会比其他算法更简单、更快速地得到解决方案。
  • 不一定能得到全局最优解:只有在某些特定问题上,贪心算法才能保证得到全局最优解。

贪心算法的应用场景:

  • 硬币找零问题:给定不同面额的硬币和一个总金额,如何用最少的硬币组成这个金额。
  • 活动选择问题:给定一系列活动的开始时间和结束时间,选择尽可能多的活动,使得活动之间不相互冲突。
  • 哈夫曼编码:用于数据压缩的哈夫曼树构建也是一个贪心算法的例子。
  • 最小生成树问题:如Prim算法和Kruskal算法。

学习贪心算法的建议:

  • 理解问题的贪心性质:分析为什么局部最优选择能导向全局最优解。
  • 实践多种贪心算法问题:通过解决不同类型的问题来加深理解。
  • 对比其他算法:了解贪心算法与动态规划、回溯等算法在解决相同问题时的不同之处。

它维护了两组节点:已经找到最短路径的节点集合和还没有找到最短路径的节点集合。算法从源节点开始,逐步将距离源节点最近的节点加入到已找到最短路径的节点集合中,并更新其他节点到源节点的距离,直到所有节点都被处理过。

在Rust中实现Dijkstra算法,我们需要考虑几个关键点:

  • 图的表示:可以使用邻接列表或邻接矩阵来表示图。
  • 优先队列:为了高效地选择下一个最短路径候选节点,通常使用优先队列(最小堆)。
  • 距离数组:用于跟踪从源节点到每个节点的当前最短距离。
  • 前驱节点数组(可选):如果需要重构最短路径,则需要此数组来跟踪到达每个节点的最短路径上的前一个节点。

实现思路拆解:

定义边和优先队列中的元素

定义图的边,以及优先队列中的元素。在这里,我们创建了一个Edge结构体来表示边,它包含目标节点的索引node和从源节点到该节点的成本cost。

#[derive(Clone, Eq, PartialEq)]
struct Edge {node: usize,cost: usize,
}

为了让Edge能够在优先队列(BinaryHeap)中按成本从小到大排序,我们需要为其实现Ord和PartialOrd特质。由于BinaryHeap是最大堆,我们通过反转比较结果来实现最小堆的效果。

impl Ord for Edge {fn cmp(&self, other: &Self) -> std::cmp::Ordering {other.cost.cmp(&self.cost).then_with(|| self.node.cmp(&other.node))}
}impl PartialOrd for Edge {fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {Some(self.cmp(other))}
}

实现Dijkstra算法。此函数接受一个邻接列表表示的图和一个起始节点索引,返回一个包含从起始节点到所有其他节点的最短路径成本的向量。

fn dijkstra(graph: &Vec<Vec<Edge>>, start: usize) -> Vec<usize> {// 初始化距离向量,所有距离初始为usize::MAXlet mut dist = vec![usize::MAX; graph.len()];let mut heap = BinaryHeap::new();// 将起始节点的距离设置为0,并加入优先队列dist[start] = 0;heap.push(Edge { node: start, cost: 0 });// 循环处理优先队列中的节点while let Some(Edge { node, cost }) = heap.pop() {// 如果当前节点的处理成本高于已知最小成本,则跳过if cost > dist[node] {continue;}// 遍历当前节点的所有邻接边for edge in &graph[node] {let new_cost = cost + edge.cost;if new_cost < dist[edge.node] {heap.push(Edge { node: edge.node, cost: new_cost }); // 直接创建并推入dist[edge.node] = new_cost; // 更新成本}}}// 返回从起始节点到所有其他节点的最短路径成本dist
}

在主函数中创建一个图,并调用dijkstra函数来计算从某个起点到图中所有其他点的最短路径成本。

fn main() {// 示例:创建一个图(这里应该是具体的图结构初始化代码)let graph = vec![vec![Edge { node: 1, cost: 2 }, Edge { node: 2, cost: 4 }],vec![Edge { node: 2, cost: 1 }],vec![Edge { node: 3, cost: 2 }],vec![],];let start = 0;let distances = dijkstra(&graph, start);println!("从节点 {} 到其他所有节点的最短路径成本:{:?}", start, distances);
}

完整代码:

use std::collections::BinaryHeap;#[derive(Clone, Eq, PartialEq)]
struct Edge {cost: usize,node: usize,
}impl Ord for Edge {fn cmp(&self, other: &Self) -> std::cmp::Ordering {other.cost.cmp(&self.cost).then_with(|| self.node.cmp(&other.node))}
}impl PartialOrd for Edge {fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {Some(self.cmp(other))}
}fn dijkstra(graph: &Vec<Vec<Edge>>, start: usize) -> Vec<usize> {let mut dist = vec![usize::MAX; graph.len()];let mut heap: BinaryHeap<Edge> = BinaryHeap::new();dist[start] = 0;heap.push(Edge { node: start, cost: 0 });while let Some(Edge { node, cost }) = heap.pop() {if cost > dist[node] {continue;}for edge in &graph[node] {let new_cost = cost + edge.cost;if new_cost < dist[edge.node] {heap.push(Edge { node: edge.node, cost: new_cost }); // 直接创建并推入dist[edge.node] = new_cost; // 更新成本}}}}dist
}fn main() {let graph = vec![vec![Edge { node: 1, cost: 2 }, Edge { node: 2, cost: 4 }],vec![Edge { node: 2, cost: 1 }],vec![Edge { node: 3, cost: 2 }],vec![],];let start = 0;let distances = dijkstra(&graph, start);println!("从节点 {} 到其他所有节点的最短路径成本:{:?}", start, distances);
}

测试

#[cfg(test)]
mod tests {use super::*;#[test]fn test_dijkstra() {// 构建一个简单的图let graph = vec![vec![Edge { node: 1, cost: 2 }, Edge { node: 2, cost: 4 }], // 从节点0到节点1和2的边vec![Edge { node: 2, cost: 1 }], // 从节点1到节点2的边vec![], // 节点2没有出边];// 打印输入图结构println!("输入图结构:");for (i, edges) in graph.iter().enumerate() {print!("节点{} -> ", i);for edge in edges {print!("(节点{}, 成本{}) ", edge.node, edge.cost);}println!();}// 执行dijkstra算法let dist = dijkstra(&graph, 0);// 打印算法输出结果println!("\n算法输出结果:");println!("{:?}", dist);// 验证结果assert_eq!(dist, vec![0, 2, 3]);}
}

节点0有两条边,一条到节点1(成本为2),另一条到节点2(成本为4)。
节点1有一条边到节点2(成本为1)。
节点2没有出边。

预期的输出是一个向量[0, 2, 3]。

Dijkstra算法的特点

  • 单源最短路径:Dijkstra算法适用于从一个源点到其他所有点的最短路径问题。
  • 非负权重限制:算法假设所有边的权重都是非负的,这是算法正确运行的前提。
  • 贪心策略:在每一步选择中,算法都会寻找未处理的最近的顶点,即它采用了贪心策略。
  • 时间复杂度:当使用优先队列(如二叉堆)时,算法的时间复杂度为O((V+E)logV),其中V是顶点数,E是边数。

应用场景

Dijkstra算法在计算机科学和相关领域中有广泛的应用,主要包括:

  • 路由算法:在网络路由协议中,如OSPF(Open Shortest Path First)使用Dijkstra算法来计算最短路径。
  • 地图服务:如Google Maps等地图和导航服务使用Dijkstra算法来找到两点之间的最短路径。
  • 图形学:在图形学中,可以用来寻找图中的最短路径,比如在像素网络中寻找最短路径。
  • 机器人路径规划:在机器人学中,Dijkstra算法可以用于寻找机器人从起点到终点的最短路径。

学习Dijkstra算法的建议

  • 理解原理:首先理解Dijkstra算法的工作原理,包括它是如何通过贪心策略来逐步确定每个顶点的最短路径。
  • 掌握实现:通过编程实践来加深理解。尝试在不同的编程语言中实现Dijkstra算法,并对比其性能。
  • 学习优化:理解不同数据结构(如优先队列、斐波那契堆)对算法性能的影响,并尝试实现这些优化版本。
  • 解决实际问题:尝试将Dijkstra算法应用于解决实际问题,如路由规划、网络流量分析等,以增强对算法应用场景的理解。
    找机器人从起点到终点的最短路径。

学习Dijkstra算法的建议

  • 理解原理:首先理解Dijkstra算法的工作原理,包括它是如何通过贪心策略来逐步确定每个顶点的最短路径。
  • 掌握实现:通过编程实践来加深理解。尝试在不同的编程语言中实现Dijkstra算法,并对比其性能。
  • 学习优化:理解不同数据结构(如优先队列、斐波那契堆)对算法性能的影响,并尝试实现这些优化版本。
  • 解决实际问题:尝试将Dijkstra算法应用于解决实际问题,如路由规划、网络流量分析等,以增强对算法应用场景的理解。
  • 对比学习:与其他路径搜索算法(如Bellman-Ford、Floyd-Warshall)进行对比学习,理解它们之间的区别和适用场景。

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

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

相关文章

arping命令详解

arping – send ARP REQUEST to a neighbour host. arping 是一个在网络中发送 ARP 请求以查找特定 IP 地址对应的 MAC 地址的命令行工具。它的功能类似于 ping 命令&#xff0c;基于ARP协议报文的交互机制&#xff0c;只能测试同一网段或子网的网络主机的连通性。 ARP 是 Add…

软件杯 深度学习实现行人重识别 - python opencv yolo Reid

文章目录 0 前言1 课题背景2 效果展示3 行人检测4 行人重识别5 其他工具6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **基于深度学习的行人重识别算法研究与实现 ** 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c…

如何使用JSONB类型在PostgreSQL中存储和查询复杂的数据结构?

文章目录 解决方案1. 创建包含JSONB列的表2. 插入JSONB数据3. 查询JSONB数据4. 创建索引以优化查询性能 示例代码结论 在PostgreSQL中&#xff0c;JSONB是一种二进制格式的JSON数据类型&#xff0c;它允许你在数据库中存储和查询复杂的JSON数据结构。与普通的JSON类型相比&…

ElasticSearch 创建索引超时(ReadTimeoutError)

报错现象 在 Python 中调用 client.indices.create 来创建 ElasticSearch 索引时&#xff0c;报如下错误&#xff1a; elastic_transport.transport - INFO - PUT http://127.0.0.1:9200/document_page?timeout60s [status:N/A duration:10.011s] elastic_transport.node_po…

《操作系统导论》第27章读书笔记:插叙:线程API

《操作系统导论》第27章读书笔记&#xff1a;插叙&#xff1a;线程API —— 2024-04-21 杭州 上午 本章讲得比较啰嗦&#xff0c;问题是本章的二级标题后面都会作为一个章节来讲&#xff0c;所以本章属于概况介绍类章节&#xff0c;另外这几个并发的章节使用的都是是POSIX线程…

(delphi11最新学习资料) Object Pascal 学习笔记---第10章第1节(为窗体添加属性)

10.1.4 为窗体添加属性 ​ 让我们来看一个使用属性进行封装的具体示例。这一次&#xff0c;我不打算创建一个自定义类&#xff0c;而是要修改IDE为你创建的可视窗体生成的窗体类&#xff1b;同时&#xff0c;我还将充分利用类完成功能。 ​ 当一个应用程序包含多个窗体时&…

【python】启动一个公司级项目的完整报错和解决方案

启动一个项目对于新手都是不容易的事情 操作 打开项目 使用pyCharm打开python项目以后&#xff0c;先找main方法&#xff0c;一般在根目录有一个.py的文件 点进去以后会让你配置Python解释器 每个项目都有自己的一个虚拟环境&#xff0c;配置自己的解释器&#xff0c;可能…

windows驱动开发-设备栈

设备栈是windows内核中非常重要的部分&#xff0c;这部分理解可以让我们在调试中节省大量的时间&#xff0c; 在windows NT体系中&#xff0c;内核所有的设备被按照连接次序加载到设备树上&#xff0c;这棵树的根节点是ROOT节点&#xff0c;每一个设备可以从当前路径一直遍历到…

QMT和Ptrade有什么区别?该如何选择?

QMT&#xff08;Quantitative Model Trading&#xff09;和Ptrade&#xff08;Professional Trading&#xff09;是两种不同的交易策略和方法&#xff0c;它们在金融市场中被广泛应用。了解它们的区别有助于投资者根据自己的需求和目标做出选择&#xff1a; QMT&#xff08;量…

将记录从excel当中导出为.sql文件,再新增到数据库

一、背景 临时遇到了一个需求&#xff0c;比如根据人员的名字查询对应记录&#xff0c;看起来还是很简单的&#xff0c;直接用select查询就可以&#xff0c;然而如果此时存在以下情况&#xff1a; 数据库根本就没有人员信息表&#xff1b;------这个倒是好操作&#xff1b;现…

AlDente Pro for mac最新激活版:电池长续航软件

AlDente Pro是一款专为Mac用户设计的电池管理工具&#xff0c;旨在提供电池安全和健康管理的一站式解决方案。它具备实时监控电池状态的功能&#xff0c;让用户随时了解电池的电量、充电次数、健康状态等信息。 AlDente Pro for mac最新激活版下载 同时&#xff0c;AlDente Pro…

Centos7 的 Open Stack T 版搭建流程 --- (四)配置 Memcached 和 RTCD

文章目录 配置 Memcached&#xff08;1&#xff09;安装 Memcached 服务器和 Python 的 Memcached 客户端controller &#xff08;2&#xff09;配置 Memcached 配置文件 六、配置 ETCD 服务&#xff08;搭建 T 版平台没有用上&#xff0c;可以跳过&#xff09;&#xff08;1&a…

分类预测 | Matlab实现CNN-LSTM-SAM-Attention卷积长短期记忆神经网络融合空间注意力机制的数据分类预测

分类预测 | Matlab实现CNN-LSTM-SAM-Attention卷积长短期记忆神经网络融合空间注意力机制的数据分类预测 目录 分类预测 | Matlab实现CNN-LSTM-SAM-Attention卷积长短期记忆神经网络融合空间注意力机制的数据分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Mat…

Vue3 + Js + Element-Plus + VueX后台管理系统通用解决方案

前言 本文是作为学习总结而写的一篇文章&#xff0c;也是方便以后有相关需求&#xff0c;可以直接拿来用&#xff0c;也算是记录吧&#xff0c;文中有一些文件的引入&#xff0c;没给出来&#xff0c;完整项目地址&#xff08;后续代码仓库放这里&#xff09; 1、layout解决方…

【Python性能优化】list、array与set

list、array与set 详述测试代码 详述 本文对比 list 与 set 在插入和取值时的性能差异&#xff0c;以提供一条什么时候该选择什么数据类型的建议。先上结果&#xff1a; array 与 list 的不同&#xff1a; 内存方面 array 是 C array 的包装&#xff0c;它直接存储数据&#xf…

【002_音频开发_基础篇_Linux音频架构简介】

002_音频开发_基础篇_Linux音频架构简介 文章目录 002_音频开发_基础篇_Linux音频架构简介创作背景Linux 音频架构ALSA 简介ASoC 驱动硬件架构软件架构MachinePlatformCodec ASoC 驱动 PCMALSA设备文件结构 ALSA 使用常用概念alsa-libALSA Open 流程ALSA Write 流程2种写入方法…

Eclipse+Java+Swing实现学生信息管理系统-TXT存储信息

一、系统介绍 1.开发环境 操作系统&#xff1a;Win10 开发工具 &#xff1a;Eclipse2021 JDK版本&#xff1a;jdk1.8 存储方式&#xff1a;Txt文件存储 2.技术选型 JavaSwingTxt 3.功能模块 4.工程结构 5.系统功能 1.系统登录 管理员可以登录系统。 2.教师-查看学生…

打破国外垄断|暴雨发布纯血国产电脑

要说现在国产手机这边已然进入纯自研模式&#xff0c;但电脑这边却还是仍未打破国外技术垄断。但就在刚刚&#xff0c;暴雨发布自研架构台式机open Station X &#xff0c;这是纯血鸿蒙系统之后国产又一款纯血产品发布&#xff01;标志的我们已经彻底打破西方在硬件及软件方面的…

c++ - 空间申请和释放 new/delete

文章目录 一、c/c内存分布二、new/delete 的使用三、malloc/free 和 new/delete 的对比四、new/delete 的实现原理五、匹配问题 一、c/c内存分布 求下面各个变量的位置 // c/c内存分布int globalVar 1; static int staticGlobalVar 1; void Test() {static int staticVar …

PyTorch与深度学习:探索现代神经网络的魅力

在科技飞速发展的今天&#xff0c;深度学习作为人工智能领域的重要分支&#xff0c;已经在图像识别、自然语言处理、语音识别等多个领域取得了突破性的进展。而PyTorch&#xff0c;作为一款开源的深度学习框架&#xff0c;以其简洁易用、动态计算图等特性&#xff0c;赢得了广大…