最近我试图解决以下问题:
我有一个非常大的文件,包含长行,我需要找到并打印出所有独特的行。
我不想使用地图或设置存储实际行,因为文件很大且行很长,所以这会导致O(N)空间复杂,常数很差(其中N是行数)。优选地,我宁愿生成一组存储指向文件中唯一的行的指针。显然,这种指针的大小(我认为64位机器上的8个字节)通常远小于内存中的行大小(我相信每个字符1个字节)。虽然空间复杂度仍为O(N),但现在常数要好得多。使用此实现,文件永远不需要在内存中完全加载。
现在,让我们说我将逐行检查文件,检查是否存在唯一性。为了查看它是否已经在集合中,我可以比较到目前为止集合指向的所有行,逐个字符地进行比较。这给出了O(N ^ 2 * L)复杂度,其中L是线的平均长度。当不关心将整行存储在集合中时,由于散列,可以实现O(N * L)复杂度。现在,当使用一组指针代替(以减少空间需求)时,我怎么能实现这一点?有一个简洁的方法吗?我唯一能想到的就是这种方法:
这是正确的方法吗?或者你有更好的方法吗?欢迎所有建议!
我可以使用一些聪明的比较对象' (或类似的东西,我还不太清楚)在每次unordered_map :: find()调用中对已存在的句子进行全自动检查?
答案 0 :(得分:2)
您的解决方案对我来说很好,因为您存储的O(唯一线条)哈希值不是N,因此它是下限。
由于您逐行扫描文件,因此您也可以对文件进行排序。现在重复的行将是连续的,您只需要检查前一行的哈希值。这种方法使用O(1)空间,但您必须先对文件进行排序。
答案 1 :(得分:2)
正如@ saadtaame的回答所说,你的空间实际上是O(唯一的行) - 根据你的使用情况,这可能是可以接受的。
虽然散列肯定有它的优点,但可以想象碰撞有很多问题 - 如果你不能有误报,那么除非你真的保留线的内容以便检查,否则它是不可行的。 / p>
您描述的解决方案是维护基于散列的集合。这显然是最直接的事情,是的,它需要在内存中维护所有独特的行。但是,这可能是也可能不是问题。该解决方案也是最容易实现的 - 您要做的就是(基于哈希的)集的任何实现都可以做到的。您只需使用std::unordered_set
,然后将每一行添加到集合中。
由于我们摒弃了各种想法,您还可以使用trie代替该集合。你可能会节省一些空间,但它仍然是O(唯一的行)。
答案 2 :(得分:0)
如果你可以利用的文件中没有一些特殊的结构,那么最后要去散列线条。这将 - 按数量级 - 比实际比较每行与文件中的每一行相比更快。
如果您的实际实施仍然太慢,您可以例如将散列限制为每行的第一部分。这会产生更多误报,但假设大多数行在前几个单词中已经偏离,它将显着加快文件处理速度(特别是,如果你受I / O限制)。