Memory management 在生成一组数字时查找其第n个最大值

Memory management 在生成一组数字时查找其第n个最大值,memory-management,selection,Memory Management,Selection,我正在编写一个程序,需要在一组数字中找到第n个最大值。这些数字是由程序生成的,但我没有足够的内存来存储N个数字。是否有一个比N更好的上限可用于存储?数字组(和N)的大小上限约为100000000 注:数字为小数,列表中可包含重复的数字 [编辑]:我的内存限制是16 MB。如果我理解得很好,您的程序的上限内存使用量是O(N)(可能是N+1)。您可以维护一个生成的值列表,这些值大于当前X(到目前为止的第n个最大值),按“最低优先”排序。一旦生成一个新的较大值,您就可以用列表的第一个元素替换当前的X,

我正在编写一个程序,需要在一组数字中找到第n个最大值。这些数字是由程序生成的,但我没有足够的内存来存储N个数字。是否有一个比N更好的上限可用于存储?数字组(和N)的大小上限约为100000000

注:数字为小数,列表中可包含重复的数字


[编辑]:我的内存限制是16 MB。

如果我理解得很好,您的程序的上限内存使用量是O(N)(可能是N+1)。您可以维护一个生成的值列表,这些值大于当前X(到目前为止的第n个最大值),按“最低优先”排序。一旦生成一个新的较大值,您就可以用列表的第一个元素替换当前的X,并将刚刚生成的值插入到列表中相应的位置。

sort-n | uniq-c,第n行应该是第n行。

这类似于另一个问题-----您可以从中得到一些答案。
逻辑同样适用于第n个最大/最小搜索。
注:我不是说这是一个重复的


因为你有很多(近10亿?)的数字,这里有另一种空间优化的方法。
让我们假设您的数字适合32位的值,因此大约10亿需要接近32GB的空间。现在,如果你能负担得起128MB的工作内存,我们可以一次性完成

  • 想象一个10亿位的向量存储为一个32位字的数组
    • 让它初始化为全零
    • 开始运行您的数字,并为数字值设置正确的位位置
    • 完成一次传递后,从该位向量开始计算第n个设定位
    • 该位的位置为您提供第n个最大数字的值
    • 实际上,您已经对流程中的所有数字进行了排序(但是,不会跟踪重复数)

  • 你能从一开始就重新生成同一组数字吗?如果是,可以对输出进行多次传递:首先查找最大值,重新启动生成器,找到小于该值的最大值,重新启动生成器,然后重复此操作,直到得到结果

    这将是一个真正的性能杀手,因为你有很多数字,需要大量的过程-但内存方面,你只需要存储2个元素(当前最大值和“限制”,你在上一次过程中找到的数字)和一个过程计数器

    您可以通过使用优先级队列查找最大的M个元素(选择一些可以放入内存的M个元素)来加快速度,从而将所需的传递次数减少到N/M


    比如说,如果你需要在15个数字的列表中找到第十大元素,你可以通过另一种方式来节省时间。因为它是第十大元素,这意味着有15-10=5个元素比这个元素小,所以您可以寻找第六小的元素。

    这是一个多路径算法(因此,您必须能够多次生成相同的列表,或者将列表存储到辅助存储)

    第一关:

    • 找到最高值和最低值。这是你的初始射程
    在第一个之后通过:

  • 将范围向上划分为10个等间距的容器。我们不需要在箱子里储存任何号码。我们只是去统计垃圾箱里的会员人数。所以我们只需要一个整数数组(或bigint——任何可以精确保存计数的数组)注意10是一个任意选择的容器数。您的样本大小和分布将决定最佳选择
  • 旋转数据中的每一个数字,增加你看到的任何一个箱子的计数
  • 找出哪个箱子里有你的答案,然后把那个箱子上面有多少个数字加到获胜箱子上面的数字中
  • 获胜箱子的顶部和底部范围是您的新范围
  • 再次循环执行这些步骤,直到您有足够的内存来保存当前存储箱中的数字
  • 最后关卡:

    • 到现在为止,您应该知道有多少数字在当前垃圾箱的上方
    • 您有足够的存储空间来获取当前垃圾箱范围内的所有数字,因此您可以旋转并获取实际数字。只需对它们进行分类,并获取正确的编号
    示例:如果您看到的范围是0.0到1000.0,则您的箱子范围将是:

     (- 0.0 - 100.0]
     (100.0 - 200.0]
     (200.0 - 300.0]
     ...
     (900.0 - 1000.0)
    
     (100.0 - 110.0]
     (110.0 - 120.0]
     etc.
    
    如果您通过计数发现您的号码在(100.0-2000.0)存储箱中,您的下一组存储箱将是:

     (- 0.0 - 100.0]
     (100.0 - 200.0]
     (200.0 - 300.0]
     ...
     (900.0 - 1000.0)
    
     (100.0 - 110.0]
     (110.0 - 120.0]
     etc.
    

    另一个多路径想法:


    只需进行二进制搜索。选择范围的中点作为第一个猜测。您的过程只需进行上/下计数即可确定下一个估计值(可以通过计数进行加权,也可以通过简单的平均值来简化代码).

    我使用最小堆优先级队列完成了此操作,但内存不足。然后您没有足够的内存来解决您的问题。我认为您不能比存储前N个数字做得更好。谢谢。我会看看是否可以在合理的时间限制内使其工作。请注意,如果您的集合包含重复项,这会使问题变得有点棘手rder,因为您不必过滤掉当前限额的所有发生情况。在这种情况下,您需要找到一种处理方法。一种方法是计算当前最大值的发生情况,然后使用临时存储来计算您错过了多少次(不在存储中).然后你用这个来相应地调整你的通行计数器(进度“跟踪器”)。我用的是双精度,因为我有十进制值。我也有重复的。我想我不明白这一点。如果任何一个数字是彼此重复的,它就失败了,对吗?对,如果我有不同的