【问题标题】:Sort in ascending or descending order (chosen arbitrarily; Prefer whichever is cheaper)按升序或降序排序(任意选择;以便宜者为准)
【发布时间】:2012-11-04 07:51:51
【问题描述】:

我有一个元素数组。这个数组可能是:

  • 随机洗牌(大约 20% 的时间)
  • 几乎按升序排序*(大约 40% 的时间)
  • 几乎按降序排序(大约 40% 的时间)

但我(事先)不知道这些情况中的哪一个适用。我更愿意将数组排序到它已经接近的顺序。

输出是升序还是降序无关紧要,但必须是其中之一(所以我可以对其进行二分查找。)

排序不必是稳定的。


一些背景信息:过程大致是这样的:

  • 填充数组
  • 按某个属性 A 排序
  • 进行一些处理(计算分位数和其他一些小东西)
  • 按其他属性 B 排序
  • 做更多处理
  • 按属性 C 排序
  • 做更多处理

A 和 B 通常相互关联(但可能正相关或负相关)。同样适用于 B 和 C。有时 A == C。

* 这里的“几乎排序”意味着大多数元素都接近它们的最终位置。但很少准确地位于它们的最终位置(有很多加性噪声,并且没有多少长排序的子序列。)仍然,在数组的开头和结尾通常有一些“异常值”,它们是顺序的不良预测因子下一种。


有没有一种算法可以利用我不偏好升序和降序这一事实来更便宜地排序(与我目前使用的 TimSort 相比?)

【问题讨论】:

  • 有什么原因不能预计算索引?
  • @Triptych:它们的寿命会很短。通常每个排序属性只使用一次,在数组被丢弃之前(只保留“做处理”步骤的结果。)

标签: algorithm sorting


【解决方案1】:

我会继续使用 Timsort(不过,一个不错的选择是 Smoothsort*),但首先要探测数组以决定是按升序还是降序排序。查看第一个和最后一个元素并进行相应的排序。如果数组未排序,则选择无关紧要;如果它是(部分)排序的,则以较宽的间隔进行探测更有可能正确检测到哪种方式。

*Smoothsort 具有与 Timsort 相同的最佳、平均和最坏情况时间,以及更好的空间复杂度。与 Timsort 一样,它专门设计用于利用部分排序的数据。

【讨论】:

  • +1(尽管“几乎排序”可能意味着任何东西,因此可能需要探测两个以上的边框元素)
  • 好奇你的理由是探测更宽的间隔更有可能检测到排序方向......
  • @Groo - 确实。也许比较第一个 k 和最后一个 k 元素。然而,在某些时候,决定订单的成本开始成为一个重要因素。
  • +1;请注意,如果您滚动自己的 Timsort,您可以在收集 minruns 时决定降序/升序。
  • @Triptych - 这只是基于 OP 对数据可能受到干扰的描述的启发式方法。该顺序与前一种排序“相关”,这对我来说表明更宽的间距更有可能检测到趋势(如果有的话)。
【解决方案2】:

另一种可能的考虑:

  • 开始进行(手动)插入排序
  • 边走边算,计算你执行的倒置次数
  • 在您完成一些固定的少量插入后,将您计算的反转次数与如果数据开始反向排序到该点发生的最大反转次数进行比较:李>
  • 如果比例接近 0,则(可能)数据接近排序。完成插入排序,它在几乎排序的数据上表现得非常好。如果您不喜欢“可能”的声音,请继续计算反转次数,并准备好在低于阈值时回退到 Timsort。
  • 如果比例接近 1,则(可能)数据几乎是反向排序的,并且您在开始时有少量已排序的元素。将它们移到末尾,反转它们,并使用反转比较器完成插入排序。
  • 否则数据是随机的,使用你喜欢的排序算法。我会说 Timsort,但因为它在几乎排序的数据上表现良好,所以 必须 有一些其他算法至少比 Timsort 在均匀混洗数据上的表现要好一点。可能是没有 Tim 的简单合并排序。

“小固定数”可以是插入排序相当快的数字,即使在不好的情况下也是如此。我猜10-20左右。对于任何给定的插入次数和任何给定的“接近 0/1”的阈值,都可以计算出均匀混洗数据中误报的概率,但我太懒了。

您说第一个和最后几个数组元素通常会逆势而上,在这种情况下,您可以将它们从初始测试插入排序中排除。

显然,这种方法在某种程度上受到了 Timsort 的启发。但是 Timsort 对包含运行的数据进行了极其优化——我试图只对接近一次大运行的数据进行极其优化(在任一方向上)。 Timsort 的另一个特点是它经过了很好的测试,我不声称要分享。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-03-18
    • 1970-01-01
    • 1970-01-01
    • 2012-11-08
    • 2023-03-07
    • 2012-12-21
    • 2018-04-25
    • 1970-01-01
    相关资源
    最近更新 更多