使用std :: collections :: BinaryHeap的就地堆

时间:2016-08-31 12:57:54

标签: sorting rust heapsort

我想在Rust中创建一个就地的heapsort函数。在标准库中,我发现std::collections::BinaryHeap看起来很有前景。我可以使用它来创建一个消耗其参数的函数:

use std::collections::BinaryHeap;

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

文档声明“将向量转换为二进制堆可以就地完成”,但是我在创建一个可以在引用上工作并且可以就地执行(heapsort<T: Ord>(list: &mut Vec<T>))时遇到问题。我可以仅使用std::collections::BinaryHeap来实现吗?

2 个答案:

答案 0 :(得分:3)

您可以mem::replace使用&#34;移动&#34; &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();
}

因此,在短时间内*list等于空向量。在这种情况下,没关系,因为创建和删除空的Vec非常便宜。

IIRC甚至还有一个箱子可以帮助借用一些*mutref值,而不会在借用期间就地使用虚拟值。但我现在无法找到它。它看起来像这样:

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

其中borrow_by_value使用一些不安全的代码(可能是ptr::read)来按行提供Vec,并将Vec带回*list更不安全的代码(可能是ptr::write)。实际的实现可能会有点复杂,以保护您不要以某种方式恐慌。我不知道。如果没有,你可能应该避免使用它。

编辑:我正在谈论的箱子是take_mut。甚至可以RFCstd::mem添加类似的内容。

答案 1 :(得分:1)

  

我无法创建一个可以在引用上工作的内容并且可以就地执行

BinaryHeap is built on top of Vec。从Vec创建新堆时,必须为其提供完整的所有权。然后它将确保向量处于良好状态以充当堆。

由于BinaryHeap不是建立在&mut Vec之上(大多数情况下会出现可怕的人体工程学),所以你不能这样做。

目前还不清楚为什么不在向量上使用slice::sort

  

文档声明“将矢量转换为二进制堆可以就地完成”

为了澄清,文档是正确的 - 有no extra memory allocation needed,因此它就位。重要的方面是BinaryHeap 拥有其数据,并不会将所有内部信息公开给全世界。

您要求的是能够在用户提供的向量上调用rebuild。对我而言,这具有可疑的用处,但您可以随时提交RFC以公开它。