我有两个文件:
一个文件存储10GB的名称“mapping.txt”:
1 "First string"
2 "Second string"
3 "Third string"
...
199000000 "199000000th string"
另一个文件以任意顺序存储来自mapping.txt的整数(存储在file.txt中):
88 76 23 1 5 7 9 10 78 12 99 12 15 16 77 89 90 51
现在我想按照上面的整数指定的顺序对“mapping.txt”进行排序,如:
88 "88th string"
76 "76th string"
23 "23rd string"
1 "1st string"
5 "5th string"
7 "7th string"
如何使用C ++完成此操作?
我知道对于文件中的每个整数,可以在“mapping.txt”中执行二进制搜索,但由于其时间复杂度为O(n log n)
,因此对于大文件来说效率不高。
我想要一种比0(n log n)
更高效的方法。
答案 0 :(得分:4)
这就是我要做的。这可能不是最有效的方式,但我想不出更好的方法。
首先,您传递一次大文件以构建每行开始的偏移量的索引。如果您的行足够长,该索引应该适合内存。
然后你传递小文件,读取每个索引,跳转到大文件中的相应位置,然后将该行复制到目标文件。
因为您的索引是连续的并且由整数索引,所以查找是常量时间。但是,无论如何,任何内存查找时间都会被磁盘搜索时间完全掩盖。
答案 1 :(得分:2)
正如塞巴斯蒂安建议的那样,试试
这具有线性时间复杂度,具体取决于两个文件的大小和线性空间复杂度,因素很小,具体取决于“mapping.txt”的行数
对于大型常规文件的快速且内存有效的顺序读取访问,请使用{API}中的mmap(2)
和madvise(2)
或其相应的构造。如果文件大于您的地址空间,请将其尽可能大地映射到块中。不要忘记在第2步(随机与顺序)中对不同访问模式的内核进行恶意软件。
如果您以后不需要它并且您的系统有内存映射,请不要将那么多内容从文件复制到堆上!
答案 2 :(得分:2)
我知道对于file.txt中的每个整数,都可以在“mapping.txt”中执行二进制搜索
正如你所说的,二进制搜索在这里没有用,除了你暴露给你的原因之外还有一个挑战,即mapping.txt不是友好的格式来执行搜索或索引。
如果可能,我建议将映射文件的格式更改为更适合直接搜索呼叫的格式。例如,您可以在包含固定长度字符串的文件中进行思考,这样您就可以计算每个条目的位置(这将在fseek调用的数量中保持不变,但请记住函数本身不会是常量)
[编辑]:
您可以采取以下措施来最小化对mapping.txt的访问:
答案 3 :(得分:1)
鉴于您有一个确切的数据输出列表,我会尝试一个数组
答案 4 :(得分:1)
最好将此问题分解为更小的问题:
n
和m
条目块(n
和m
可以是相同的大小或不同)m
- 您正在操作的file.txt的偏移量)并对来自这些索引的那些索引执行映射排序各种mapping.txt块。m
output-X.txt文件,您可以将这些文件合并到实际的输出文件中。由于您的数据是ASCII,因此将固定窗口映射到任一文件会很麻烦,因此将两者分成较小的文件会很有帮助。
答案 5 :(得分:1)
这是mergesort的一个非常好的候选者。 这将是O(n log n),但大多数算法都不会超过它。 您只需使用索引文件来更改密钥比较。 你可以在任何体面的算法教科书中找到合并排序,它很适合对磁盘进行外部排序,因为要排序的文件大于内存。
如果你真的必须击败O(n log n),则传递一个文件并构建一个由密钥索引的哈希表,每个行的位置。然后读取索引文件,并使用哈希表来定位每一行。 从理论上讲,这将是O(n +大常数)。 不过我看到了一些问题:什么是n?这将是一个很大的哈希表。由于“大常量”非常大,实现可能比O(n log n)解决方案慢得多。即使您将文件映射为有效访问,也可能会进行大量分页。