差异算法?

时间:2009-04-30 06:37:34

标签: algorithm diff vcdiff

我一直看起来很疯狂,因为有关diff算法的解释很有效。

我最接近的是this link to RFC 3284(来自几篇Eric Sink博客文章),其中以完全可理解的术语描述了存储差异结果的数据格式。但是,它没有提及程序如何在进行差异时达到这些结果。

我试图从个人的好奇心来研究这个问题,因为我确信在实现差异算法时必须进行权衡,有时当你看到差异并且想知道“为什么diff程序选择了这个作为改变而不是那个?“......

在哪里可以找到最终输出VCDIFF的有效算法的描述? 顺便说一句,如果您碰巧找到了SourceGear的DiffMerge使用的实际算法的描述,那就更好了。

注意:最长的公共子序列似乎不是VCDIFF使用的算法,看起来他们在使用他们使用的数据格式时做得更聪明。

5 个答案:

答案 0 :(得分:161)

An O(ND) Difference Algorithm and its Variations是一篇精彩的论文,你可能想从那里开始。它包括伪代码和执行差异所涉及的图遍历的可视化。

第4节引入了对算法的一些改进,使其非常有效。

成功实施此功能将为您提供工具箱中非常有用的工具(也可能是一些非常好的经验)。

生成所需的输出格式有时会很棘手,但如果您对算法内部有了解,那么您应该能够输出所需的任何内容。您还可以引入启发式方法来影响输出并进行某些权衡。

Here is a page,其中包含一些文档,full source code以及使用上述算法中的技术的diff算法示例。

source code似乎紧密遵循基本算法,易于阅读。

还有一些准备输入,你可能会觉得有用。当您按字符或标记(单词)进行区分时,输出会有很大差异。

祝你好运!

答案 1 :(得分:33)

我首先会看一下diff的实际源代码,GNU会available

对于理解该源代码的实际工作原理,该软件包中的文档引用了启发它的论文:

  

基本算法在“An O(ND)差分算法及其变体”,Eugene W.Myers,'Algorithmica'Vol。 1986年第1号,第251-266页;并在“文件   比较程序“,Webb Miller和Eugene W. Myers,'Software - Practice and Experience'Vol.15 No. 11,1985,pp.1025-1040。算法独立发现,如”近似字符串匹配的算法“中所述。 ,E。Ukkonen,“信息与控制”,第64卷,1985年,第100-118页。

阅读论文然后查看实现的源代码应该足以理解它是如何工作的。

答案 2 :(得分:29)

请参阅https://github.com/google/diff-match-patch

  

“Diff Match和Patch库   提供强大的算法来执行   同步所需的操作   纯文本。 ...目前可用   在Java,JavaScript,C ++,C#和   的Python“

另请参阅wikipedia.org Diff page和 - “Bram Cohen: The diff problem has been solved

答案 3 :(得分:11)

我来到这里寻找差异算法,然后我自己实现了。对不起,我不知道vcdiff。

Wikipedia:从最长的公共子序列获得类似差异的输出只是一小步:如果一个项目在子序列中不存在但在原始项目中存在,则必须将其删除。 (下面的' - '标记。)如果子序列中不存在但存在于第二个序列中,则必须将其添加到。('+'标记。)

LCS algorithm here的精彩动画。

链接到快速LCS ruby implementation here

我的缓慢而简单的红宝石适应性如下。

def lcs(xs, ys)
  if xs.count > 0 and ys.count > 0
    xe, *xb = xs
    ye, *yb = ys
    if xe == ye
      return [xe] + lcs(xb, yb)
    end
    a = lcs(xs, yb)
    b = lcs(xb, ys)
    return (a.length > b.length) ? a : b
  end
  return []
end

def find_diffs(original, modified, subsequence)
  result = []
  while subsequence.length > 0
    sfirst, *subsequence = subsequence
    while modified.length > 0
      mfirst, *modified = modified
      break if mfirst == sfirst
      result << "+#{mfirst}"
    end
    while original.length > 0
      ofirst, *original = original
      break if ofirst == sfirst
      result << "-#{ofirst}"
    end
    result << "#{sfirst}"
  end
  while modified.length > 0
    mfirst, *modified = modified
    result << "+#{mfirst}"
  end
  while original.length > 0
    ofirst, *original = original
    result << "-#{ofirst}"
  end
  return result
end

def pretty_diff(original, modified)
  subsequence = lcs(modified, original)
  diffs = find_diffs(original, modified, subsequence)

  puts 'ORIG      [' + original.join(', ') + ']'
  puts 'MODIFIED  [' + modified.join(', ') + ']'
  puts 'LCS       [' + subsequence.join(', ') + ']'
  puts 'DIFFS     [' + diffs.join(', ') + ']'
end

pretty_diff("human".scan(/./), "chimpanzee".scan(/./))
# ORIG      [h, u, m, a, n]
# MODIFIED  [c, h, i, m, p, a, n, z, e, e]
# LCS       [h, m, a, n]
# DIFFS     [+c, h, +i, -u, m, +p, a, n, +z, +e, +e]

答案 4 :(得分:9)

根据Emmelaich给出的链接,Neil Fraser's website (one of the authors of the library)上的差异策略也有很大的影响。

他介绍了基本策略,并在文章的最后进展到Myer的算法和一些图论。