题目描述
假如有一个 1G 大小的文件,文件里每一行是一个词,每个词的大小不超过 16byte,要求返回出现频率最高的 100 个词。内存大小限制是 10M。
解决方案
方案一
- 分治处理:将大文件分割成多个小文件,确保每个小文件能被加载到 10M 内存中。可以根据单词的哈希值对文件进行划分,将相同哈希值范围的单词写入同一个小文件。
- 统计词频:依次处理每个小文件,使用哈希表(字典)统计每个小文件中单词的出现频率。
- 维护小顶堆:对于每个小文件的统计结果,使用一个大小为 100 的小顶堆来维护当前出现频率最高的 100 个单词。如果堆的大小小于 100,则直接将单词及其频率插入堆中;如果堆的大小已经达到 100,且当前单词的频率大于堆顶元素的频率,则替换堆顶元素并调整堆。
- 合并结果:处理完所有小文件后,堆中存储的就是整个大文件中出现频率最高的 100 个单词。
如果这个 1G 的大文件中有某个词词频过高,可能导致小文件大小超过 10m。这种情况下该怎么处理呢?
方案二
- 外部排序:使用多路归并排序对大文件进行排序,这样相同的单词肯定是紧挨着的。多路归并排序对大文件进行排序的步骤如下:
- 将文件按照顺序切分成大小不超过 2m 的小文件,总共 500 个小文件
- 使用 10MB 内存分别对 500 个小文件中的单词进行排序
- 使用一个大小为 500 大小的堆,对 500 个小文件进行多路排序,结果写到一个大文件中
- 其中第三步,对 500 个小文件进行多路排序的思路如下:
- 初始化一个最小堆,大小就是有序小文件的个数 500。堆中的每个节点存放每个有序小文件对应的输入流。
- 按照每个有序文件中的下一行数据对所有文件输入流进行排序,单词小的输入文件流放在堆顶。
- 拿出堆顶的输入流,并其下一行数据写入到最终排序的文件中,如果拿出来的输入流中还有数据的话,那么将这个输入流再一次添加到栈中。否则说明该文件输入流中没有数据了,那么可以关闭这个流。
- 循环这个过程,直到所有文件输入流都没有数据为止。
- 维护小顶堆:在合并统计结果的过程中,使用一个大小为 100 的小顶堆来维护当前出现频率最高的 100 个单词。