简体   繁体   中英

In-place heapsort using std::collections::BinaryHeap

I'd like to create an in-place heapsort function in Rust. In the standard library I found std::collections::BinaryHeap that looked promising. I am able to use it to create a function consuming its argument:

use std::collections::BinaryHeap;

fn heapsort<T: Ord>(list: Vec<T>) -> Vec<T> {
    let heap = BinaryHeap::from(list);
    heap.into_sorted_vec()
}

The docs state that "converting a vector to a binary heap can be done in-place", but I am having trouble creating one that works on a reference and can do it in-place ( heapsort<T: Ord>(list: &mut Vec<T>) ). Can I achieve it using only std::collections::BinaryHeap ?

You can use mem::replace for "moving" something out from behind a &mut reference:

use std::collections::BinaryHeap;
use std::mem;

fn heapsort<T: Ord>(list: &mut Vec<T>) {
    let tmp = mem::replace(list, Vec::new());
    let heap = BinaryHeap::from(tmp);
    *list = heap.into_sorted_vec();
}

So, for a short while *list is made equal to an empty vector. In this case it's ok because creating and dropping empty Vec s is very cheap.

IIRC there is even a crate out there that helps borrowing some *mutref by value, without using a dummy value in-place during the borrow. But I can't find it right now. It would look something like this:

fn heapsort<T: Ord>(list: &mut Vec<T>) {
    borrow_by_value(list, |tmp| {
        BinaryHeap::from(tmp).into_sorted_vec()
    });
}

where borrow_by_value uses some unsafe code (probably ptr::read ) to give you the Vec by value and will put a Vec back to *list with some more unsafe code (probably ptr::write ). The actual implementation might be a little more complicated to protect you from panics somehow. I don't know. And if not, you should probably avoid using it after all.

Edit: The crate I was talking about is take_mut . There is even an RFC to add something like this to std::mem .

I am having trouble creating one that works on a reference and can do it in-place

BinaryHeap is built on top of Vec . When you create a new heap from a Vec , you have to give it complete ownership. It will then ensure that the vector is in a good state to act as a heap.

Since a BinaryHeap is not built on top of a &mut Vec (which would mostly have horrible ergonomics), you cannot do that.

It's unclear why you don't just use slice::sort on the vector.

the docs state that "converting a vector to a binary heap can be done in-place"

To clarify, the documentation is correct - there's no extra memory allocation needed , thus it is in-place. The important aspect is that the BinaryHeap owns its data and doesn't expose all the internals out to the world.

What you are asking for is the ability to call rebuild on a user-supplied vector. To me, this has dubious usefulness, but you could always submit an RFC to expose it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM