Java 我们如何引用文件的特定行?

Java 我们如何引用文件的特定行?,java,algorithm,file,data-structures,hash,Java,Algorithm,File,Data Structures,Hash,我在读关于算法问题的书,其中一个是: 有一个包含数百万行数据的文件,有两行 都是一样的。这些行太长了,可能无法放入内存。发现 两条相同的线 建议的解决方案是读取部分行,并为每行创建哈希。 例如,通过构建第1行的第1部分(可在内存中读取)的散列,然后构建第1行的第2部分到第1行的第N部分的散列,来构建第1行的散列。 将哈希存储在文件或哈希表中。对于任何相同的哈希值,请比较行。如果线是一样的,我们就解决了 虽然我对这个解决方案有很高的理解,但我不知道如何实现它。如何将散列与文件中的特定行关联?这是语

我在读关于算法问题的书,其中一个是:

有一个包含数百万行数据的文件,有两行 都是一样的。这些行太长了,可能无法放入内存。发现 两条相同的线

建议的解决方案是读取部分行,并为每行创建哈希。
例如,通过构建第1行的第1部分(可在内存中读取)的散列,然后构建第1行的第2部分到第1行的第N部分的散列,来构建第1行的散列。
将哈希存储在文件或哈希表中。对于任何相同的哈希值,请比较行。如果线是一样的,我们就解决了

虽然我对这个解决方案有很高的理解,但我不知道如何实现它。如何将散列与文件中的特定行关联?这是语言实现的细节吗?

例如,在Java中,我们如何解决这个问题?

真正的答案是购买更多内存。在Java2GB中可以拥有的最长字符串,它将适合现在的机器。您可以用不到200美元的价格购买32GB


但是为了解决这个问题,我建议你

  • 找到每行的偏移量
  • 找到长度相同的线(使用偏移差)
  • 计算具有相同长度的行的64位或更长哈希值
  • 对于具有相同哈希的行,进行逐字节比较
注意:如果没有足够的内存来缓存整个文件,这将需要很长时间。如果您有一台32 GB的计算机,并且它有一个64 GB的文件,那么每次传递大约需要20分钟,并且有多个传递


1) 哪个API可以找到偏移量

计算已读取的字节数,这就是偏移量

2) 真正的答案是“购买更多内存”项目经理不同意这一点。你有不同的经历吗

我向他们指出,如果他们认为可以很好地利用资源,我可以花一天的时间节省100美元的可重用内存,这可能会花费他们1000美元以上(即使这不是我得到的报酬)。我让他们决定;)


我8岁的儿子在一台个人电脑上有8GB的内存,因为他的内存花了我24英镑。但是你是对的,有些项目经理认为8GB对于一个每小时花费那么多的专业人员来说太多了!?我有16GB的电脑,我不使用它来运行任何严肃的东西,因为我在256GB的机器上工作。现在,您可以购买容量为2 TB的机器,这对于大多数应用程序来说都是多余的。;)

虽然我同意解决方法是利用现代技术,并利用当今内存的廉价性,但问题在于锻炼大脑,了解如何在给定的约束条件下解决问题

你提到的散列非常简单。 java解决方案可以利用一些隐藏的东西,这些东西可能会掩盖实际发生的事情,因此我将首先解释解决方案,然后解释java实现

通用解决方案:

散列(如SHA1、MD5等)通过压缩输入生成整数。假设您只能在每行中存储前MB的字符

  • 您将迭代每一行,获得第一个MB的字符,并将其传递给哈希算法(例如MD5)
  • 然后将散列映射为键,将行号列表/数组映射为值
  • 在第一次传递之后,任何具有匹配的前MB字符的行都将以相同的哈希结束,从而位于映射中的相同列表中
  • 要准备第二次通过,请搜索地图并剔除仅包含一个行号的任何列表
  • 然后,通过从地图中的其余条目中编译行号来创建行号列表,这些行号将是第二遍中唯一选中的行号
  • 第二步,从行列表中的每一行提取第二MB字符,对它们进行散列,并以与第一步相同的方式将它们放入映射中
  • 迭代映射中的条目,剔除只有一个行号的散列条目
  • 重复第二步,但增加字符块(MB),使其与密码一致
  • 当您到达一个过程,其中只有一个具有多个行号的哈希,并且该哈希只有两个元素时,这些行就是相同的两行
这本质上是一个树搜索

Java方法: Java有一个名为HashMap的类,它自动对密钥进行散列。通过使用

HashMap<String,ArrayList<Integer>>
HashMap
对于您的主地图,您只需执行每个调用即可

  • map.get(mbBlock).add(行号);当然,您应该检查这是否是第一次使用这个键,这样您就不会得到空指针异常
  • 每次通过后,剔除只包含一行的条目
  • 在剩下的几行重复,直到只剩下两个行号
  • 获取每行的前k个字符,其中k是可配置的。进行散列以查找可能具有相同行的几组行

  • 根据第一步的结果(缩小搜索范围),在每个较小的组上运行算法,以获得下一个k个字符

  • 如果不是在最坏的情况下,搜索范围在每一轮之后都会大大缩小


  • 算法的诀窍在于将大问题分解为小问题,并充分利用前面步骤的结果。

    通过映射,可以将散列值映射为一行,这样键就是散列值,值就是行号。只需存储字节偏移量。@Cratylus:常规文件IO(或NIO)API(streams).@Cratylus:不读取文件就无法读取文件。@Cratylus:不需要一次存储整行来计算换行符。1)使用哪个API来查找偏移量?2)
    真正的答案是购买更多内存
    项目经理并不真正同意这一点