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.