【问题标题】:Limited Sort/Filter Algorithm有限的排序/过滤算法
【发布时间】:2011-09-01 17:30:35
【问题描述】:

我有一个相当大的元素列表(数千个)。

我有一个可以接受或不接受元素的过滤器。

我想要前 100 个满足过滤器的元素。

到目前为止,我已经先对结果进行了排序,然后取出了满足过滤器的前 100 个。这背后的基本原理是过滤器并不完全快速。

但是现在,排序步骤比过滤步骤花费的时间更长,所以我想以某种方式将它们组合起来。

是否有一种算法可以结合排序/过滤的关注点,以获得满足过滤器的前 100 个结果,而不会产生对所有元素进行排序的成本?

【问题讨论】:

  • 不排序如何定义“top”?
  • @dlev:你仍然需要排序......如果你知道你只需要几个“最高”值。

标签: performance algorithm sorting filter


【解决方案1】:

我的直觉是从列表中选择前 100 个元素(比排序便宜得多,使用您最喜欢的 QuickSelect 变体)。通过过滤器运行它们,产生n 成功和100-n 失败。如果 n < 100 则重复选择列表其余部分顶部的 100-n 元素:

k = 100
while (k > 0):
    select top k from list and remove them
    filter them, yielding n successes
    k = k - n

一切都很好,这运行的时间与列表的长度成正比,因为每个选择步骤都在那个时间运行,并且所需的选择步骤数取决于过滤器的成功率,而不是直接取决于列表。

不过,我预计这会有一些不好的情况。如果几乎所有元素都无法通过过滤器,那么它比仅对所有元素进行排序要慢得多,因为您最终会选择数千次。因此,如果它看起来很糟糕,您可能需要一些标准来解决问题,然后退回到对整个列表进行排序。

它还有一个问题,它可能会在最后进行大量的小选择,因为如果过滤条件与排序条件无关,我们预计 k 会呈指数衰减。因此,您可以通过在每个步骤中选择多于 k 个元素来改进它。比如说,k 除以过滤器的预期成功率,再加上一个小常数。如果没有可用于预测的领域知识,则基于过去性能的期望,以及通过实验选择的小常数以避免寻找最后几个元素的大量步骤。如果您最终在任何步骤中通过过滤器的项目多于您仍在寻找的数量(即 n > k),则从当前批次的成功中选择前 k 个,您就完成了。

由于 QuickSelect 为您提供前 k 个而不对这些 k 进行排序,因此如果您需要按顺序排列前 100 个元素,则需要对 100 个元素进行最终排序。

【讨论】:

  • +1 这正是我要写的。为了完整性 - 预期的运行时间是 O(np + k log k) 时间和 O(np) 过滤器应用程序,其中 p 是任何元素通过过滤器的概率。顺便说一句,您不需要随着窗口的大小呈指数增长 - 如果您假设元素以概率 p 独立通过过滤器,那么概率确实呈指数下降。
  • 是的,我的噩梦场景“几乎所有元素都无法通过过滤器”只能在列表变长时为真,如果过滤器不独立于列表长度和元素的排序顺序,而是在事实上,在问题的更大版本中变得更加挑剔。我认为,处理任何此类相互关系都超出了简单复杂性分析的范围。所以我很高兴你为此目的假设独立,并假设它完全可以省去对那个杀手案的担忧。
  • 实际上,您评论中的p 不是元素失败过滤器的概率吗?也就是说,如果过滤器接受大多数东西,那么我们应该需要更少的过滤器应用程序,而不是更多。
  • 我喜欢这个解决方案,尽管我同意你不应该在每一步都选择 k,因为你得到 99 的噩梦会在第一次命中时传递,而下一次传递恰好有最差的分数,你基本上有 n^2 发生。我可能会以固定大小的块来执行此操作,因为过滤器的成功概率在很大程度上取决于执行搜索的用户。
  • 另外,如果我们预计某个百分比会失败,那么让初始选择大于 k 可能是有意义的。我将尝试各种分块方法并报告。
【解决方案2】:

我已经解决了这个确切的问题,方法是使用二叉树进行排序并在插入过程中保持当前节点左侧的元素计数。详情请参阅http://pub.uni-bielefeld.de/publication/2305936(图 4.4 等)。

【讨论】:

    【解决方案3】:

    如果我理解正确,你有两个选择:

    • 选择 100 个元素 - 过滤检查的 N 次操作。然后 100(lg 100) 进行排序。

    • 排序然后选择 100 个元素 - 至少 N(lg N) 进行排序,然后选择。

    第一个听起来更短,然后排序然后选择。

    【讨论】:

    • 虽然过滤整个列表在渐近时间上更快,但过滤的实际操作具有与之相关的非平凡成本。在某个临界点,先过滤会更快,但在大多数情况下,先排序会更快。我认为接受的解决方案相当优雅地解决了这两个问题。
    【解决方案4】:

    我可能会先过滤,然后将过滤结果插入优先级队列。跟踪 PQ 中的项目数量,在插入后,如果它大于您要保留的数量(在您的情况下为 100),则弹出最小的项目并丢弃它。

    【讨论】:

      【解决方案5】:

      Steve 建议使用 Quicksort 是一个很好的建议。

      1 读入前 1000 个左右的元素。
      2 对它们进行排序并选择第 100 个最大的元素。
      3 以第 2 步中的元素为基准,对整个文件运行一次快速排序。
      4 选择快速排序结果的上半部分进行进一步处理。

      保证您在 Quicksort 的单次通过的上半部分中至少有 100 个元素。假设前 1000 个可以合理地代表整个文件,那么您应该在第 4 步得到大约十分之一的原始元素。

      【讨论】:

      • 我建议使用快速选择 (en.wikipedia.org/wiki/…),而不是快速排序。围绕枢轴进行分区的步骤是相同的​​,但 quickselect 仅使用它来查找顶部的 k 元素,它不会对数据进行排序。
      • 我的错误。对不起。这与我试图用“一次快速排序”短语表达的观点相同。
      猜你喜欢
      • 1970-01-01
      • 2019-05-31
      • 2018-12-01
      • 2021-08-04
      • 1970-01-01
      • 2020-09-08
      • 1970-01-01
      • 2020-12-12
      • 1970-01-01
      相关资源
      最近更新 更多