易语言资源网 - 做最全的易语言资源下载社区
精易论坛授权登录

【首发】【Myers Diff】【差异纯算法】文章差异 劲爆算法   [复制链接]

    2022-12-09 08:38:20
    2022开源大赛(第七届)
    易语言资源网
    2043 次浏览
    来源链接

什么是直观的 diff

我们先简单定义一下,什么是 diff:diff 就是目标文本和源文本之间的区别,也就是将源文本变成目标文本所需要的操作。
Myers算法由Eugene W.Myers在1986年发表的一篇论文中提出,是一个能在大部分情况产生”最短的直观的“diff的一个算法。

diff 与图搜索

”寻找最短的直观的diff”是一个非常模糊的问题,首先,我们需要把这个问题抽象为一个具体的数学问题,然后再来寻找算法解决。抽象的过程交给算法科学家了,抽象的结果是:寻找diff的过程可以被表示为图搜索

什么意思呢?还是以两个字符串,src=ABCABBA,dst=CBABAC为例,根据这两个字符串我们可以构造下面一张图,横轴是src内容,纵轴是dst内容,那么图中每一条从左上角到右下角的路径,都表示一个diff。向右表示删除,向下表示新增,对角线则表示原内容保持不动

根据图中形成的线路,我们可以选择一条路径看看它的效果

  • (0, 0) -> (1, 0)
  • (1, 0) -> (2, 0) -> (3, 1)
  • (3, 1) -> (3, 2) -> (4, 3) -> (5, 4)
  • (5, 4) -> (6, 4) -> (7, 5)
  • (7, 5) -> (7, 6)


这条路径代表的 diff 如下:

- A- B  C+ B  A  B- B  A+ C

  • 现在,“寻找 diff” 这件事,被抽象成了“寻找图的路径”了。那么,“最短的直观的” diff 对应的路径有什么特点呢?

    • 路径长度最短(对角线不算长度)
    • 先向右,再向下(先删除,后新增)



三个概念根据 Myers 的论文,他提出了三个概念:

  • snake: 一条snake代表走一步。例如从(0,0)->(0,1) / (0,0)->(1,0) / (0,1)->(0,2)->(2,4) 这分别为三条snake,走对角线不计入步数。
  • k line: 定义 k = x - y (我们可以写成 y = x - k,是相同斜率的平行斜线组成的一个集合)
  • d contour: 走一步算一个d

Myers 算法

Myers 算法就是一个能在大部分情况产生”最短的直观的“ diff 的一个算法,算法原理如下。
  • 首先,定义参数 d 和 k,d 代表路径的长度,k 代表当前坐标 x - y 的值。定义一个”最优坐标“的概念,最优坐标表示 d 和 k 值固定的情况下,x 值最大的坐标。x 大,表示向右走的多,表示优先删除。
  • 还是用上面那张图为例。我们从坐标 (0, 0) 开始,此时,d=0,k=0,然后逐步增加 d,计算每个 k 值下对应的最优坐标。
  • 因为每一步要么向右(x + 1),要么向下(y + 1),对角线不影响路径长度,所以,当 d=1 时,k 只可能有两个取值,要么是 1,要么是 -1。
  • 当 d=1,k=1 时,最优坐标是 (1, 0)。
  • 当 d=1,k=-1 时,最优坐标是 (0, 1)。
  • 因为 d=1 时,k 要么是 1,要么是 -1,当 d=2 时,表示在 d=1 的基础上再走一步,k 只有三个可能的取值,分别是 -2,0,2。
  • 当 d=2,k=-2 时,最优坐标是 (2, 4)。
  • 当 d=2,k=0 时,最优坐标是 (2, 2)。
  • 当 d=2,k=2 时,最优坐标是 (3, 1)。
  • 以此类推,直到我们找到一个 d 和 k 值,达到最终的目标坐标 (7, 6)。
  • 下图横轴代表 d,纵轴代表 k,中间是最优坐标,从这张图可以清晰的看出,当 d=5,k=1 时,我们到达了目标坐标 (7, 6),因此,”最短的直观的“路径就是 (0, 0) -> (1, 0) -> (3, 1) -> (5, 4) -> (7, 5) -> (7, 6),对应的 diff 如下。

现在我们可以知道,其实 Myers 算法是一个典型的”动态规划“算法,也就是说,父问题的求解归结为子问题的求解。要知道 d=5 时所有 k 对应的最优坐标,必须先要知道 d=4 时所有 k 对应的最优坐标,要知道 d=4 时的答案,必须先求解 d=3,以此类推。

实现

算法原理知道以后,实现便是一件简单的事情了,基本流程如下:
  • 迭代 d,d 的取值范围为 0 到 n+m,其中 n 和 m 分别代表源文本和目标文本的长度(这里我们选择以行为单位)
  • 每个 d 内部,迭代 k,k 的取值范围为 -d 到 d,以 2 为步长,也就是 -d,-d + 2,-d + 2 + 2…
  • 使用一个字典 v,以 k 值为索引,存储最优坐标的 x 值
  • 将每个 d 对应的 v 字典存储起来,后面回溯的时候需要用
  • 当我们找到一个 d 和 k,到达目标坐标 (n, m) 时就跳出循环
  • 使用上面存储的 v 字典(每个 d 对应一个这样的字典),从终点反向得出路径


  • 最后补充一句,市面上使用的是标准 Myers 算法的一个变体。标准的算法有一个很大的缺点,就是空间消耗很大,因为我们需要存储每一个 d 对应的 v 字典。如果输入文件比较大,这样的空间开销是不能接受的。因此 Myers 在他的 论文 中,同时提供了一个算法变体,这个变体需要的空间开销要小得多。但是在某些情况下,变体产生的 diff 会和标准算法有所不同。也就是说,如果你按照上面的算法实现的程序,出来的结果和市面上的结果有所不同是正常的。


源码演示

全中文,步步注释

文本差异(有窗口)软件截图

调用模块

有窗口版本,调用两个模块;
无窗口版本,纯源码。

附件上带了模块,一个是内存优化,来自论坛的大佬!

一个是exui的,因为调用了富文本框的一些东西



点我下载 (已有 62 次下载)

引用模块


源码文件名 模块文件名
Myers diff 可视化.e
内存加速优化v1.6.1.ec
ExuiFunction20220513.ec
Myers diff 无窗口.e
内存加速优化v1.6.1.ec


引用支持库


源码文件名 支持库文件名 支持库标识
Myers diff 可视化.e 系统核心支持库 5.7 d09f2340818511d396f6aaf844c7e325
特殊功能支持库 3.1 A512548E76954B6E92C21055517615B0
EXUI++界面库20220526 2022.5 5014D8FA6DCA40b68FA626D8186666EB
多线程支持库 2.0 5F99C1642A2F4e03850721B4F5D7C3F8
Myers diff 无窗口.e 系统核心支持库 5.7 d09f2340818511d396f6aaf844c7e325
特殊功能支持库 3.1 A512548E76954B6E92C21055517615B0
内存加速优化v1.6.1_模块源码.e 系统核心支持库 5.7 d09f2340818511d396f6aaf844c7e325


[错误报告]   上一篇:按照片拍摄日期批量重命名工具...     下一篇:多行文本滚屏器【文本滚动直播助手】...