How can I implement a min-heap of f64 with Rust's BinaryHeap?

隐身守侯 提交于 2019-12-18 21:51:33

问题


I want to populate a binary heap with floats--more specifically, I'd like to implement a min-heap.

It seems that floats do not support Ord and thus aren't usable out of the box. My attempts to wrap them have so far failed. However it seems that if I could wrap them then I could also implement Ord in such a way that it would effectively make BinaryHeap a min-heap.

Here's an example of a wrapper I tried:

#[derive(PartialEq, PartialOrd)]
struct MinNonNan(f64);

impl Eq for MinNonNan {}

impl Ord for MinNonNan {
    fn cmp(&self, other: &MinNonNan) -> Ordering {
        let ord = self.partial_cmp(other).unwrap();
        match ord {
            Ordering::Greater => Ordering::Less,
            Ordering::Less => Ordering::Greater,
            Ordering::Equal => ord
        }
    }
}

The problem is pop returns the values as though it were a max-heap.

What exactly do I need to do to populate a BinaryHeap with f64 values as a min-heap?


回答1:


Instead of writing your own MinNonNan, consider using the ordered-float crate + the std::cmp::Reverse type.

type MinNonNan = Reverse<NotNan<f64>>;

Since you are #[derive]ing PartialOrd, the .gt(), .lt() etc methods still compare normally, i.e. MinNonNan(42.0) < MinNonNan(47.0) is still true. The Ord bound only restricts you to provide strictly-ordered types, it doesn't mean the implementation will use .cmp() instead of </>/<=/>= everywhere, nor the compiler will suddenly change those operators to use the Ord implementation.

If you want to flip the order, you need to reimplement PartialOrd as well.

#[derive(PartialEq)]
struct MinNonNan(f64);

impl PartialOrd for MinNonNan {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        other.0.partial_cmp(&self.0)
    }
}

impl Ord for MinNonNan {
    fn cmp(&self, other: &MinNonNan) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}



回答2:


Working Example

use std::cmp::Ordering;
use std::collections::BinaryHeap;

#[derive(PartialEq)]
struct MinFloat(f64);

impl Eq for MinFloat {}

impl PartialOrd for MinFloat {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        other.0.partial_cmp(&self.0)
    }
}

impl Ord for MinFloat {
    fn cmp(&self, other: &MinFloat) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

fn main() {
    let mut minheap = BinaryHeap::new();
    minheap.push(MinFloat(2.0));
    minheap.push(MinFloat(1.0));
    minheap.push(MinFloat(42.0));
    if let Some(MinFloat(root)) = minheap.pop() {
        println!("{:?}", root);
    }
}


来源:https://stackoverflow.com/questions/39949939/how-can-i-implement-a-min-heap-of-f64-with-rusts-binaryheap

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!