这本质上是这个问题的一个更受限制的版本。
假设我们有一个非常大的文本文件,其中包含大量行。
我们需要从文件中随机选择一行,概率一致,但是有一些限制:
- 因为这是一个软实时应用程序,我们无法遍历整个文件。选择应该花费恒定的时间。
- 由于内存限制,无法缓存该文件。
- 因为文件允许在运行时更改,所以不能假定文件的长度是一个常数。
我的第一个想法是使用lstat()
调用来获取总文件大小(以字节为单位)。fseek()
然后可以用于直接访问随机字节偏移量,获得类似 O(1) 访问文件的随机部分的内容。
问题是我们不能再执行诸如读取到下一个换行符并收工之类的事情,因为这会产生一个偏向于长行的分布。
我解决这个问题的第一个想法是读取前“n”个换行符(如果需要,回绕到文件的开头),然后从这个较小的集合中选择一个概率一致的行。可以安全地假设文件的内容是随机排序的,所以这个子样本在长度方面应该是统一的,并且由于它的起点是从所有可能的点中统一选择的,它应该代表文件中的统一选择作为所有的。所以,在pseudo-C中,我们的算法看起来像:
lstat(filepath, &filestat);
fseek(file, (int)(filestat.off_t*drand48()), SEEK_SET);
char sample[n][BUFSIZ];
for(int i=0;i<n;i++)
fgets(sample[i], BUFSIZ, file); //plus some stuff to deal with file wrap around...
return sample[(int)(n*drand48())];
这似乎不是一个特别优雅的解决方案,而且我不完全相信它会是统一的,所以我想知道是否有更好的方法来做到这一点。有什么想法吗?
编辑:进一步考虑,我现在很确定我的方法不统一,因为起点更有可能在较长的单词内,因此不统一。棘手!