如何在有限的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
相比的最大允许元素,我可以想到两个选项:
- 使数组尽可能大且未排序,定期检索最小的元素。
- 有一个大小为
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 }
结构。
问题:
一个函数 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
相比的最大允许元素,我可以想到两个选项:
- 使数组尽可能大且未排序,定期检索最小的元素。
- 有一个大小为
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 }
结构。