【问题标题】:How do I create a BinaryHeap that pops the smallest value, not the largest?如何创建弹出最小值而不是最大值的 BinaryHeap?
【发布时间】:2019-02-02 02:10:11
【问题描述】:

我可以使用std::collections::BinaryHeap 使用pop最大最小 顺序迭代结构的集合,但我的目标是迭代集合从小到大。

我已经成功逆转了Ord 的实现:

impl Ord for Item {
    fn cmp(&self, other: &Self) -> Ordering {
        match self.offset {
            b if b > other.offset => Ordering::Less,
            b if b < other.offset => Ordering::Greater,
            b if b == other.offset => Ordering::Equal,
            _ => Ordering::Equal, // ?not sure why compiler needs this
        }
    }
}

现在BinaryHeap 返回Items 从最小到最大。看到这不是预期的 API,这是一个不正确或容易出错的模式吗?

我意识到LinkedList 会给我pop_front 方法,但我需要在插入时对列表进行排序。这是更好的解决方案吗?

【问题讨论】:

  • 这不是预期的 API — 你到底是什么意思?
  • 我的意思是文档 ion 说接下来会出现最伟大的项目,所以当我实现这个反转时,对于(代码的)新读者来说,这将是意想不到的行为

标签: sorting rust binary-heap


【解决方案1】:

颠倒堆内类型的顺序很好。但是,您不需要实现自己的订单反转。相反,请酌情使用std::cmp::ReverseOrdering::reverse

如果在某个字段较大时您的类型实际上小于另一个值是有意义的,请实现您自己的Ord

impl Ord for Item {
    fn cmp(&self, other: &Self) -> Ordering {
        self.offset.cmp(&other.offset).reverse()
    }
}

如果您不希望更改您的类型的顺序,请在将其放入 BinaryHeap 时翻转顺序:

use std::{cmp::Reverse, collections::BinaryHeap};

fn main() {
    let mut a: BinaryHeap<_> = vec![1, 2, 3].into_iter().collect();
    if let Some(v) = a.pop() {
        println!("Next is {}", v);
    }

    let mut b: BinaryHeap<_> = vec![1, 2, 3].into_iter().map(Reverse).collect();
    if let Some(Reverse(v)) = b.pop() {
        println!("Next is {}", v);
    }
}
Next is 3
Next is 1

另见:

[a LinkedList] 是更好的解决方案吗?

99.9% 的情况下,链表不是更好的解决方案。

【讨论】:

    猜你喜欢
    • 2013-02-17
    • 2021-11-29
    • 2016-07-14
    • 2019-04-06
    • 1970-01-01
    • 2023-01-16
    • 2014-12-08
    • 2012-01-19
    • 1970-01-01
    相关资源
    最近更新 更多