【问题标题】:How can I sort a LinkedList with just the standard library?如何仅使用标准库对 LinkedList 进行排序?
【发布时间】:2015-08-16 10:58:19
【问题描述】:

Vec 提供了一种排序方法(通过Deref 实现),但LinkedList 没有。 Rust 标准库中是否有通用算法允许对LinkedLists 进行排序?

【问题讨论】:

  • 我怀疑是这样,销毁列表、分配另一个容器并重新创建另一个列表是可行的解决方案吗?因为排序链表效果不好。
  • 为什么说排序链表效果不好?合并排序是对链表进行排序的好方法...
  • @wspeirs 因为链表很慢。使用LinkedList → Vec → LinkedList 几乎肯定会比就地排序更快。为什么你还有LinkedList
  • @wspeirs:理论和实践的问题在于它们只是在理论上是相同的。在这种情况下,虽然您确实可以使用链表获得 O(N log N) 复杂性,但实际上由于缓存未命中和恒定因素,它通常很慢。 C++ 提供了list.sort(),因为std::sort 需要随机访问迭代器,因此需要专门的版本;但是后来 C++ 还提供了list.size(),它阻止了 O(1) 拼接,所以我不确定这是一个好主意。
  • @Veedrac 我们还没有找到一种方法来使类似RandomAccessIterator 的抽象工作允许排序。当前的 RAI 提供只读访问权限。

标签: rust


【解决方案1】:

我认为没有内置的方法可以做到这一点。但是,您可以将列表内容移动到Vec,对其进行排序并将其转回链表:

let mut vec: Vec<_> = list.into_iter().collect();
vec.sort();
let list: LinkedList<_> = vec.into_iter().collect();

这个想法甚至没有看起来那么糟糕 - 请参阅here。虽然存在用于对链表进行排序的相对较快的算法确实,但它们不会像平面数组排序那样为您提供尽可能多的缓存性能。

【讨论】:

  • 我在这里唯一担心的是消耗然后重新分配列表意味着释放/重新分配内存。我想知道向量中的工作是否可以代理,即不是传输列表元素,而是将引用放入向量中,然后对向量进行排序实际上会改变列表元素。 . 或者至少,不是使用列表,而是用“假人”替换它的元素,然后用排序值再次替换假人。
  • 是的,重新分配是对的。我认为像read_into_vec&lt;T&gt;(list: &amp;mut LinkedList&lt;T&gt;, vec: &amp;mut Vec&lt;T&gt;) unsafe 函数及其对应的read_into_list&lt;T&gt;(vec: &amp;mut Vec&lt;T&gt;, list: &amp;mut LinkedList&lt;T&gt;)(也是不安全的)这样的东西可以在不释放它们的情况下移动元素,但在这里应该非常小心恐慌和析构函数。
  • 代理也会破坏基于 CPU 缓存的加速,因为它需要通过双重间接访问列表元素。
  • if 'T: Copy' 那么你在创建 vec 时只能进行一次分配,然后只需将 vec 的值复制到链表的值上
【解决方案2】:

参见this question,它非常相似,但语言不特殊。


不久前我研究了这个主题(使用 C,但也适用于 Rust)。

除了转换为向量和排序,然后转换回链表。合并排序通常是对链表进行排序的最佳方法。

双链表和单链表都可以使用相同的方法(双向链接没有优势)

这是一个例子,originally from this answer,我是ported to C

这是一个很好的merge-sort的例子,但是经过一些进一步的调查,我发现Mono's eglib mergesort要更有效,尤其是当列表已经部分排序时。

这是portable version of it

将它从 C 移植到 Rust 应该不会太难。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-09-20
    • 2011-04-11
    • 1970-01-01
    • 2022-01-25
    • 2019-05-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多