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

使用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::MAX
    let mut dist = vec![usize::MAX; graph.len(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值