问题是,给定一个包含40亿个整数的输入文件,提供一个算法来生成一个未包含在文件中的整数,假设只有10 MB的内存。
搜索了一些解决方案,其中一个解决方案是将整数存储到位向量块中(每个块表示40亿个范围内的特定整数范围,块中的每个位表示一个整数),并使用另一个计数器每个块,计算每个块中的整数数。因此,如果整数的数量小于整数的块容量,则扫描块的位向量以找到缺少整数的块。
我对此解决方案的困惑是,当块计数器阵列占用与位向量相同的内存时,提到最佳最小占用空间。我很困惑为什么在这种情况下它是最佳的最小足迹?
以下是我提到的计算细节
Let N = 2^32.
counters (bytes): blocks * 4
bit vector (bytes): (N / blocks) / 8
blocks * 4 = (N / blocks) / 8
blocks^2 = N / 32
blocks = sqrt(N/2)/4
提前谢谢,
林
答案 0 :(得分:5)
在您提出的解决方案中,有两个阶段:
计算每个块中的整数数
这使用4*(#blocks)
个字节的内存。
使用位向量表示块中的整数。
这使用(blocksize/8)
个字节的内存,即(N/blocks)/8
。
如前所述,将2设置为相等会产生blocks = sqrt(N/32)
。
这是最佳的,因为所需的内存是每个阶段所需内存的最大值(必须同时执行)。在第一阶段之后,您可以忘记计数器,除了要搜索第2阶段的块。
如果计数器达到容量时饱和,那么每个计数器实际上不需要4个字节,而是需要3个字节。当计数器超过块中的整数时,计数器达到容量。
在这种情况下,阶段1使用3*blocks
内存,阶段2使用(N/blocks)/8
。因此,最优是blocks = sqrt(N/24)
。如果N
为40亿,则块数约为12910,块大小为每块309838个整数。这适合3个字节。
您提出的算法仅在所有输入整数都不同时才有效。如果整数不明显,我建议你简单地使用随机候选整数集方法。在随机候选整数集方法中,您可以随机选择1000个候选整数,并检查输入文件中是否找不到任何整数。如果失败,您可以尝试找到另一组随机整数。虽然这样的最差情况表现不佳,但对于大多数输入来说,平均情况会更快。例如,如果输入整数的覆盖率为99%的可能整数,那么平均而言,有1000个候选整数,其中10个将无法找到。您可以伪随机选择候选整数,这样您就不会重复候选整数,并且还要保证在固定次数的尝试中,您将测试所有可能的整数。
如果每次都检查sqrt(N)
个候选整数,那么最差情况下的性能可能与N*sqrt(N)
一样好,因为您可能需要扫描所有N个整数sqrt(N)
次。 / p>
如果您使用此备选方案,则可以避免最坏情况时间,如果它不适用于第一组候选整数,则切换到建议的解决方案。这可能会提供更好的平均案例性能(这是排序中首先使用快速排序的常用策略,然后切换到heapsort,例如,如果看起来存在最坏情况输入)。
答案 1 :(得分:1)
# assumes all integers are positive and fit into an int
# very slow, but definitely uses less than 10MB RAM
int generate_unique_integer(file input-file)
{
int largest=0
while (not eof(input-file))
{
i=read(integer)
if (i>largest) largest=i
}
return i++; #larger than the largest integer in the input file
}