如何在有限的space的情况下select最少N个元素?

how to select least N elements with limited space?

问题:

一个函数 f returns 个元素,一次一个,顺序未知。我要 select 最少 N 个元素。函数 f 被调用了很多次(我正在通过非常复杂的搜索 space 进行搜索)并且我没有足够的内存来存储每个输出元素以供将来排序。

显而易见的解决方案:

在内存中保留一个包含 N 个元素的向量,并在每个 f() 上搜索最小值和最大值并可能替换一些东西。这可能适用于非常小的 N 井。不过,我正在寻找更通用的解决方案。

目前我的解决方案:

我虽然关于使用 priority_queue 来存储比方说 2N 值并在每个 2N 步骤后减少上半部分。

伪代码:

while (search goes on)
    for (i=0..2N)
        el = f()
        pust el to the priority queue
    remove N greatest elements from the priority queue
select N least elements from the priority queue

我认为这应该可行,但是,我觉得它一点也不优雅。也许已经有某种数据结构可以处理这个问题。如果只是修改 priority_queue 以丢弃不适合保存范围的元素,那就太好了。

您能否向我推荐一个现有的 std C++ 数据结构或鼓励我实施上面建议的解决方案?或者也许有一些我想不到的伟大而优雅的技巧。

您想在通过调用函数获得的总共 K 个元素中找到 least n 个元素。每次调用函数 f() 时,您都会得到一个元素,并且您想在其中存储 least n 个元素,而不存储从函数中获得的总 k 个元素,因为 k 太大了。

您可以定义一个 heap or priority_queue 来存储目前找到的 least n。只需将 f() 的返回项添加到 pq 并在其大小变为 n+1.

时弹出最大的元素

总复杂度为 O(K*log(n)),所需 space 为 O(n)。 (如果我们忽略 pq 所需的一些额外的 space)

备选方案是使用数组。根据与 N 相比的最大允许元素,我可以想到两个选项:

  1. 使数组尽可能大且未排序,定期检索最小的元素。
  2. 有一个大小为 N 的数组,最后按最大元素排序。

选项 1 会让你每次填满数组时用 O(n log n) 次对数组进行排序。每个 n - N 个元素(第一次除外)都会发生这种情况,产生 (k - n) / (n - N) 排序,导致 k 个总元素的 O((k - n) / (n - N) n log n) 时间复杂度,n 个元素在数组中,N 个元素被选中。所以对于 n = 2N,如果我没记错的话,你会得到 O(2*(k - 2N) log 2N) 时间复杂度。

选项 2 让您保持数组(大小 N)在最后按最大元素排序。每次获取一个元素,可以快速(O(1))查看是否比上一个小。使用二进制搜索,您可以在 O(log N) 时间内找到元素的正确位置。但是,您现在需要将新元素之后的所有元素向右移动一位。这需要 O(N) 时间。所以你最终得到理论上的 O(k*N) 时间复杂度。考虑到计算机喜欢使用同质数据访问(缓存和其他东西),这可能比堆更快,即使它是数组支持的。

如果您的元素很大,即使您使用堆(除非它是列表支持的),您最好使用 { coparison_value; actual_element_pointer } 结构。