我正在编写一个程序,而不是需要在一组数字中找到第 N 个最大值。这些数字是由程序生成的,但我没有足够的内存来存储 N 个数字。是否有比 N 更好的存储上限?数字组(以及 N)大小的上限约为 100,000,000。
注意:数字是小数,列表可以包含重复项。
[编辑]:我的内存限制是 16 MB。
我正在编写一个程序,而不是需要在一组数字中找到第 N 个最大值。这些数字是由程序生成的,但我没有足够的内存来存储 N 个数字。是否有比 N 更好的存储上限?数字组(以及 N)大小的上限约为 100,000,000。
注意:数字是小数,列表可以包含重复项。
[编辑]:我的内存限制是 16 MB。
你能从一开始就重新生成同一组数字吗?如果是这样,您可以对输出进行多次传递:首先找到最大值,重新启动生成器,找到小于该值的最大值,重新启动生成器,然后重复此操作,直到得到结果。
这将是一个真正的性能杀手,因为你有很多数字并且需要很多遍 - 但是在内存方面,你只需要存储 2 个元素(当前最大值和“限制”,数字你在最后一次通过时找到的)和一个通行证柜台。
您可以通过使用优先级队列来查找最大的 M 个元素(选择一些可以放入内存的 M)来加快速度,从而将所需的通过次数减少到 N/M。
例如,如果您需要在 15 个数字的列表中找到第 10 个最大的元素,则可以通过相反的方式来节省时间。由于它是第 10 大元素,这意味着有 15-10=5 个元素比该元素小 - 所以您可以寻找第 6 小的元素。
这是一个多通道算法(因此,您必须能够多次生成相同的列表,或者将列表存储到辅助存储中)。
第一关:
在第一个之后通过:
最后一关:
示例:如果您看到的范围是 0.0 到 1000.0,那么您的 bin 范围将是:
(- 0.0 - 100.0]
(100.0 - 200.0]
(200.0 - 300.0]
...
(900.0 - 1000.0)
如果您通过计数发现您的号码在 (100.0 - 2000.0] 箱中,那么您的下一组箱将是:
(100.0 - 110.0]
(110.0 - 120.0]
etc.
另一个多通道想法:
只需进行二进制搜索。选择范围的中点作为第一个猜测。您的通行证只需要进行高于/低于计数来确定下一个估计值(可以按计数加权,或为代码简化而采用简单的平均值)。
这类似于另一个问题 - C 程序在不排序的情况下搜索数组中的第 n 个最小元素?——你可能会得到一些答案。
该逻辑同样适用于第 N 个最大/最小搜索。
注意:我并不是说这是重复的。
由于您有很多(近 10 亿?)数字,这是空间优化的另一种方法。
让我们假设您的数字适合 32 位值,因此大约 10 亿将需要接近 32GB 的空间。现在,如果你能负担得起大约 128MB 的工作内存,我们可以一次性完成。
如果我理解得很好,你的程序的内存使用上限是 O(N)(可能是 N+1)。您可以维护一个大于当前 X(迄今为止的第 N 个最大值)的生成值列表,按最低优先排序。一旦生成了一个新的更大的值,您可以将当前的 X 替换为列表的第一个元素,并将刚刚生成的值插入到其在列表中的相应位置。
排序-n | uniq -c 并且第 N 行应该是第 N 行