【问题标题】:Merge sort in java and copying array, still nlogn?java中的合并排序和复制数组,还是nlogn?
【发布时间】:2016-04-19 05:49:13
【问题描述】:

我看过一些java中合并排序的实现,似乎拆分部分通常是通过创建2个新数组,左右并将左右部分分别复制到这些数组来完成的。

我的问题是:这仍然给了我们 nlogn 时间,对吗?因为现在每个拆分将有 n+n 时间(拆分数组的 n 时间,合并数组的 n 时间)并且有 logn 拆分,所以我们有 2nlogn,它仍然是 nlogn。这是正确的吗?

【问题讨论】:

  • 是的。 O(2n logn) 仍然是 O(n logn)。
  • 另外,数组分割发生在原地。本身不是新数组。
  • 我正在尝试实现就地数组划分,但它看起来有点乱。您需要跟踪原始数组的开始和结束索引,对吗?实现起来似乎并不太难,但与只创建一个新的左数组和一个新的右数组相比,它肯定会出现更多错误。
  • @Kevin 我明白了。但这就是所谓的优化。
  • 可惜主流语言没有数组切片D Slices

标签: java mergesort


【解决方案1】:

您查看了哪些实现? JDK 使用的主要排序算法是DualPivotQuicksort(用于原始数组)、TimSortComparableTimSort(用于Object 数组/集合),以及ArraysParallelSortHelpers 中用于并发排序的难以理解的巫术。

所有这些类都提供了 QuickSort 或 MergeSort 的高度调整的实现(或者在并行情况下 "CilkSort",这听起来像是一个并发友好的 MergeSort)。这些算法通常都是 O(n log(n)) - 它是 impossible to do better than O(n log(n)),对您的输入没有额外的限制。

至于这些算法是否通常花费 O(n) 时间在临时存储之间来回复制值,这在很大程度上是一个个案问题。在可能的情况下,这些实现肯定会尽量避免使用 O(n) 额外的内存和时间来进行线性复制,但通常这样的工作实际上并不是瓶颈。例如 CilkSort 使用辅助“工作空间数组”在连续阶段中来回复制值,这使得执行不变量变得更容易,因为“前”阶段始终处于可靠状态。尽管如此,实现还是尽可能避免不必要的数组副本。

在公共 API 级别,我们会注意到 Collections.sort() 调用 .toArray(),对数组进行排序,然后将值复制回原始 List。这同样只是一个实际的优化——对数组进行排序并执行两个线性副本比处理修改List in-的所有方法调用(以及可能效率低下的List 实现,例如LinkedList)更快。地点。

【讨论】:

    猜你喜欢
    • 2012-08-17
    • 2013-04-02
    • 2017-04-19
    • 1970-01-01
    • 2014-05-17
    • 1970-01-01
    • 1970-01-01
    • 2018-12-05
    • 2013-03-11
    相关资源
    最近更新 更多