【问题标题】:An efficient sorting algorithm for almost sorted list containing time data?包含时间数据的几乎排序列表的有效排序算法?
【发布时间】:2012-06-16 12:20:21
【问题描述】:

这个名字真的说明了一切。我怀疑插入排序是最好的,因为它通常是大多数排序数据的最佳排序。但是,由于我对数据了解得更多,因此有可能还有其他类型的数据值得关注。所以其他相关的信息是:

1) 这是时间数据,这意味着我推测可以为数据排序创建一个有效的散列。 2)数据不会同时存在。相反,我将阅读可能包含单个向量或十几个或数百个向量的记录。我想在 5 秒的窗口内输出所有时间。因此,在我插入数据时进行排序的排序可能是一个更好的选择。 3) 内存不是大问题,但CPU速度是因为这可能是系统的瓶颈。

鉴于这些条件,除了插入排序之外,任何人都可以提出一种可能值得考虑的算法吗?另外,如何定义“大部分排序”来决定什么是好的排序选项?我的意思是我如何查看我的数据并决定'这不像我想象的那样排序,也许插入排序不再是最好的选择'?任何链接到考虑了过程复杂性的文章,更好地定义了相对于学位数据的复杂性,我们将不胜感激。

谢谢

编辑: 谢谢大家的信息。我现在将使用简单的插入或合并排序(无论我已经预先编写过哪个)。但是,一旦接近优化阶段,我将尝试其他一些方法(因为它们需要更多的努力来实现)。感谢您的帮助

【问题讨论】:

  • 我想您正在寻找一种排序算法?
  • 就像你说的......插入排序。 sorting-algorithms.com/nearly-sorted-initial-order
  • 你的时间数据的范围和粒度是多少?
  • 范围和宏大变化。必须从多个来源中读取,并且“排序”的范围、梯度甚至级别都可能因来源而异。

标签: c++ algorithm sorting insertion-sort


【解决方案1】:

您可以对大小为n 的列表进行排序,其中k 元素在O(n + k lg k) 时间不合适。

见:http://www.quora.com/How-can-I-quickly-sort-an-array-of-elements-that-is-already-sorted-except-for-a-small-number-of-elements-say-up-to-1-4-of-the-total-whose-positions-are-known/answer/Mark-Gordon-6?share=1

基本思路是这样的:

  • 遍历数组的元素,构建一个递增的子序列(如果当前元素大于或等于子序列的最后一个元素,则将其附加到子序列的末尾。否则,丢弃当前元素和子序列的最后一个元素)。这需要O(n) 时间。
  • 由于k 元素不合适,您将丢弃的元素不超过2k
  • 使用O(k lg k) 排序算法(如合并排序或堆排序)对被丢弃的2k 元素进行排序。
  • 您现在有两个排序列表。在O(n) 时间合并列表,就像在合并排序的合并步骤中一样。

总体时间复杂度 = O(n + k lg k)

整体空间复杂度 = O(n)

(如果可以合并到O(1)空间,这可以修改为在O(1)空间运行,但这绝不是微不足道的)

【讨论】:

    【解决方案2】:

    在没有完全理解问题的情况下,Timsort 可能符合要求,因为您声称您的数据大部分已经排序。

    【讨论】:

      【解决方案3】:

      如果您的操作系统或 C 库提供了合并排序功能,它很可能已经处理了在 O(N) 时间内运行的给定数据是部分有序(在任何方向上)的情况。

      否则,您可以从您最喜欢的 BSD 操作系统中复制可用的归并排序。

      【讨论】:

        【解决方案4】:

        有许多自适应排序算法专门设计用于对大部分排序的数据进行排序。忽略您正在存储日期的事实,您可能希望将smoothsort 或笛卡尔树排序视为可以对在最坏情况 O(n log n) 时间和最佳情况 O( n) 时间。 Smoothsort 还具有只需要 O(1) 空间的优点,就像插入排序一样。

        利用一切都是日期并因此可以转换为整数的事实,您可能希望使用三个枢轴的中值选择来查看二进制快速排序(MSD 基数排序)。该算法具有最佳情况 O(n log n) 性能,但具有非常低的常数因子,使其非常具有竞争力。它最坏的情况是 O(n log U),其中 U 是每个日期的位数(可能是 64),这还不错。

        希望这会有所帮助!

        【讨论】:

          【解决方案5】:

          您可以采用您建议的选项 (2) - 在插入元素时对数据进行排序。

          使用skip list,按时间排序,升序维护您的数据。

          • 一旦有新主菜到达 - 检查它是否大于最后一个 元素(简单快捷)如果是 - 只需附加它(在跳过列表中很容易做到)。这 对于这些情况,skip list 平均需要添加 2 个节点,并且将是 O(1) on 这些案例的平均值。
          • 如果元素不大于最后一个元素 - 将其添加到 跳过列表作为标准插入操作,即O(logn)

          这种方法将产生O(n+klogn) 算法,其中k 是乱序插入的元素数。

          【讨论】:

          • 只要您跟踪最大元素,您也可以使用平衡的 BST 来执行此操作。我认为从内存的角度来看,BST 方法可能会更好,特别是如果您使用像展开树或替罪羊树这样的东西,每个节点正好有两个指针。
          • @templatetypedef:虽然我相信它可以做到——我发现跳过列表比 BST 更直观。如果 BST 不是自平衡的 - 它很可能会衰减为所描述输入的高度较大的树,并且搜索无序的元素将是扩展的。另一方面,至少在我看来,在添加新的最大值后重新平衡树不如将元素附加到跳过列表那么直观。
          • @amit 您可以单独对已排序的项目进行排序,然后再将它们合并,而不是使用数据结构对已排序项目旁边的不适当项目进行排序。有关更多详细信息,请参阅我的答案。结果是O(n + k lg k) 算法。
          【解决方案6】:

          如果你实现自然版本,我会抛出merge sort,如果你有任何问题,你会得到O(N) 的最佳情况和O(N log N) 的典型和最坏情况。插入你会得到O(N^2) 的最坏情况和O(N) 的最佳情况。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2023-03-30
            • 2023-03-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多