查找文件中出现的每个整数值的绝对计数
Posted
技术标签:
【中文标题】查找文件中出现的每个整数值的绝对计数【英文标题】:find absolute counts for each integer value that occurs in a file 【发布时间】:2011-08-05 02:46:30 【问题描述】:在最近的一次采访中被问到
有一个包含一百万个整数的日志文件。每个整数的长度为 32 位。日志文件中的特定整数值可能会重复。您可以按顺序读取日志文件。您还可以顺序读取和写入临时文件;可以随时打开的文件数量没有限制。但是,在任何给定时间,您在内存中最多可以保留 2000 个整数。
我被要求生成一个直方图,显示日志文件中出现的每个整数值的绝对计数,并说明每个整数必须加载到内存中的次数的顺序复杂度上限
【问题讨论】:
我希望这份工作做得很好,我会告诉他们坚持下去 【参考方案1】:打开 232 个临时文件,每个整数一个。按顺序读取日志文件一次。每当读取整数 n 时,将“1”写入临时文件编号 n。然后通过所有临时文件生成直方图。每个整数只被读入一次内存,所以它是 O(n) 算法。
【讨论】:
是的,O(n) 有一个 非常大 常数! 是的,哈哈,我想看看可以打开所有文件的操作系统 :) 答案是个玩笑,我认为问题不是很好 :) 这是个玩笑,但它回答了所提出的问题,时间为 O(n)。这是我给出的“答案”,希望他们随后将“无限制”改写为某个合理的数字。【参考方案2】:这是一个令人困惑的问题。您不能只读取 2,000 个数字,对它们进行排序,然后写入临时文件吗?这样做 500 次,然后进行 N 路合并。每个数字将被加载到内存中两次。
如果您必须在只有 2 GB RAM 的计算机上对 TB 大小的文件进行排序,您会做同样的事情。
【讨论】:
@gradbot:确实如此,尽管人们会期望操作系统会缓冲很多。 4K 缓冲区将保存其中一个临时文件的一半内容。如果您不能指望缓冲,那么进行简单的合并可能会更好:写入第一个缓冲区,读取下一个并将其与第一个合并以创建一个新的临时文件。读取下一个缓冲区并合并等。基本上,您正在执行 499 次 2 路合并,而不是单个 N 路合并。有许多不同的方法可以进行合并。 确实,对于现代硬盘缓存大小(多 MB),顺序访问时间与随机访问时间并没有多大关系。 如果您知道数据包含相对较高的重复次数,您可以使用合并排序存储键值对,合并相等的键(键将是整数值之一)并将它们的值相加(计数整数外观)。 @gradbot:如果您不关心每次顺序搜索数组的成本,这是一个值得的优化。如果没有读取缓冲,那么这绝对是一个值得优化的优化,因为每次点击都会节省一次搜索,而一次搜索将花费与多次搜索相同的时间。【参考方案3】:-
在内存中保留 2000 int = 大小
缓冲区
对文件的读/写没有限制 = 每个数字计数将存储在一个文件中。
32 位长度的数量 = 每个 文件是一个数字和文件名 是代表的 32 位 整数(可以使用整数值 也一样)
显示直方图(表示没有顺序 需要)
伪代码:
count = 2000
HashMap<number, number> = new
code:readbuffer
while count != 0
read NextNumber
if HashMap.HasKey NextNumber then HashMap[NextNumber]++
else HashMap[NextNumber]=1
count --;
end while
code:flushbuffer
foreach Key in HashMap
if exists FileName Key.ToBinnary
FileValue += HashMap[HashKey]
else WriteNewFile FileName=Key.toBinnay; SetValue = 1
end foreach
code: histogram
each file name is the number;
each file value is the count.
成本:读取缓冲区
读取的序列数 = 2M(M = 百万)
Map.HasKey = (在2000年的记录中搜索key,最坏的情况是数字不存在,SUMMARY(∑2000)x2M)
SetValue on Map 与上面的成本相同
总计:(2M)+(2Mx∑2000)x2
成本:flushbuffer File.exists 2M
成本:直方图 2M
总计 = 6M + 4Mx∑2000
【讨论】:
如果文件包含重复的 3,000 个值会怎样?也就是说,文件的内容是1,2,3,...3000,1,2,3,3000,etc.
你最终会读取每个临时文件超过300次。
天哪,您要创建最多 2^32 个文件吗?我不认为这是一个成功的答案。
@Jim Mischel 是的,但没什么大不了的,因为您正在读取 2^32 个数字,缓冲区只有 2000 个值。这还不是最坏的情况。最糟糕的是每个数字出现一次。
@Nick Johnson,这就是这里每个人都提出的建议,实际上也是唯一可能的回应。只有另一种方法可以使它更快。在二叉树中组织文件名(如下所示)。这样可以更快地生成直方图。
这远非唯一可能的答案 - 请参阅 @Jim 的更明智的外部排序以获得更好的解决方案。【参考方案4】:
实现基于文件的 B-tree。
文件名是 GUID。
文件内容为: 数见 数数 左节点文件 右节点文件
经过一次后,复杂度可以从 B-tree 推导出来。
您的直方图隐含在结构中。
【讨论】:
以上是关于查找文件中出现的每个整数值的绝对计数的主要内容,如果未能解决你的问题,请参考以下文章