简体   繁体   English

使用std :: collections :: BinaryHeap进行就地堆排序

[英]In-place heapsort using std::collections::BinaryHeap

I'd like to create an in-place heapsort function in Rust. 我想在Rust中创建一个就地堆排序函数。 In the standard library I found std::collections::BinaryHeap that looked promising. 在标准库中,我发现std::collections::BinaryHeap看起来很有希望。 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>) ). 文档指出,“可以将向量转换为二进制堆可以就地完成”,但是我在创建一个可以在引用上工作并且可以就地进行处理的堆时遇到了麻烦( heapsort<T: Ord>(list: &mut Vec<T>) )。 Can I achieve it using only std::collections::BinaryHeap ? 我可以仅使用std::collections::BinaryHeap来实现它吗?

You can use mem::replace for "moving" something out from behind a &mut reference: 您可以使用mem::replace&mut引用后面“移动”某些内容:

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. 因此,在短时间内*list等于一个空向量。 In this case it's ok because creating and dropping empty Vec s is very cheap. 在这种情况下可以,因为创建和删除空Vec非常便宜。

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. IIRC甚至有一个板条箱,可以按值借用一些*mutref ,而无需在借用时就地使用虚拟值。 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 ). 其中borrow_by_value使用一些不安全的代码(可能是ptr::read )为您提供按值分配的Vec ,并将带有一些更不安全的代码(可能是ptr::write )的Vec返回到*list 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 . 编辑:我正在谈论的板条箱是take_mut There is even an RFC to add something like this to std::mem . 甚至有一个RFC可以在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 . BinaryHeap 建立在Vec之上 When you create a new heap from a Vec , you have to give it complete ownership. Vec创建新堆时,必须赋予它完全所有权。 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. 由于BinaryHeap并非基于&mut Vec (大多数情况下具有人体工程学),因此您不能这样做。

It's unclear why you don't just use slice::sort on the vector. 目前尚不清楚为什么不对向量使用slice::sort

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. 重要的方面是BinaryHeap 拥有其数据,并且不会向内部公开所有内部信息。

What you are asking for is the ability to call rebuild on a user-supplied vector. 您要提供的功能是能够在用户提供的rebuild上调用rebuild To me, this has dubious usefulness, but you could always submit an RFC to expose it. 对我来说,这很有用,但是您始终可以提交RFC来公开它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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