硬着头皮学数据结构和算法之Myers算法

写在前面

对比功能在工作中用的还是比较多的,比如git diff:

以及常用的文本对比工具,如beyond compare:

解决此类场景的算法,叫做文本差分算法,本文要介绍的Myers就是其中的一种算法。

1:什么是文本差分算法?

要想定义文本差分算法,首先要介绍下编辑脚本的概念,我们知道,一串字符A变为一串字符B是经过不断的删除字符和插入字符的操作来完成的,例如AB->ACD就要经过如下的插入和删除操作(不唯一,仅示例):

复制代码
1:删除B
2:插入C
3:插入D

文本差分算法就可以定义为用来计算出标记脚本的算法。人有好有坏,算法也是如此,评价文本差分算法好坏的指标主要有两个,第一个就是编辑脚本的长度,自然越短越好。对于源序列 S = ABCABBA 目标序列 T = CBABAC,如下左边的编辑脚本就要优于右边的编辑算法:

myers算法也是要求解最短编辑脚本。

而最短编辑脚本的长度是和最长公共子序列长度有关系的,这也很好理解,相同的子序列越多需要编辑的部分自然越少,具体计算方式如下:

复制代码
源序列 
S = ABCABBA length m = 7
目标序列
T = CBABAC  length n = 6

最长公共子序列(不唯一)
C = CBBA    length LC = 4 

最短编辑脚本:m+n-2LC=5

评价一个文本查分算法优劣的第二个指标是可读性,毕竟编辑脚本对应的展示效果最终是给人看的,如下左边的可读性就要优于右边:

虽然都是最短编辑脚本得出的结果,但是第一种明显可读性更好,因为第一种连续的相同操作更长,对人更友好,不需要过多的思维转换。

总的来说,Myers就是要找到最短的可读性最高的编辑脚本的文本查分算法。

2:Myers介绍

为了实现可编程,Myers将问题转化了图搜索问题,以如下的源序列和目标序列为例

复制代码
源序列 
S = ABCABBA length m = 7
目标序列
T = CBABAC  length n = 6

转化为如下的二维网格,称之为编辑图:

其中横向每一步代表删除一个数据,纵向的每一步代表插入一个数据。比如(0,0)->(0,1)代表将源序列索引位置0的字符删掉,(3,3)->(3,4)代表将目标字符索引位置3的字符B插入到源序列的索引位置3(注意这里是插入,不占用原有索引位置,而是整体后移),如下图:

为了更加清晰来看一个程序的例子,源序列ABC,目标序列CBAB,按照如下的编辑脚本执行:

代码com.dong.business.logic.algorithm.myers.v1.MyersV1:

运行看一下:

复制代码
+C
+B
-A
-B
+A
+B
-C
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

按照这种编辑脚本,我们的操作数是7,但明显不是最有的,比如下面这种操作数就是5:

其中斜线的部分代表不需要占用任何的操作数,因为先+B,再-B,显然是有些脱裤子放屁了。此时程序实现参考这里,执行效果:

复制代码
+C
-A
 B
+A
+B
-C
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

当然以上都是我们为了说明问题,具体的还是要看myers算法是如何做的。

2.1:Myers的重要概念

  • D-path
    完整路径的一个中间状态,注意这里的路径要求是最短路径,而非所有路径,其中的D,代表到此中间状态经过的操作数。如下是2-path的示例:

    所以D-path是一个中间状态,代表了到达此状态的最短操作数路径。
  • snake
    操作数为1的路径,注意可以是中间的一个子路径,另外规定,如果后继是斜线则要一直走下去,直到没有斜线,即后继不能有斜线。如下都是snake:

    所以snake就是操作数为1的路径,只不过有的包含斜线,有的不包含斜线(此时以斜线结尾)。
  • line
    从左上到右下的四十五度线,可以用k=x-y来描述这条线,即k值就代表了某个line,如下图示例:

我们可以用以D-path为横轴,k-line号为纵轴来画一个坐标系,则如下的路径:

表示在这个坐标系中就如下图:

可以看到是一直在向右走的。

TODO 动态规划实现

写在后面

源码 。

参考文章列表

业务开发算法 50 讲 。

相关推荐
蓝悦无人机1 小时前
无人机系列之飞控算法:从PID到AI,飞行控制的核心进化
人工智能·算法·无人机·飞控系统
憨波个1 小时前
【说话人日志】DiariZen
人工智能·深度学习·算法·语音识别
用户7341681035481 小时前
被忽视的输入:为什么变工况故障诊断需要引入控制回路信号?
算法
垆边人似月.1 小时前
华为机试题 :最长递增子序列题目
数据结构·c++·算法·华为
动词ing1 小时前
【题目练习】算法 组合总和
算法
程序员-Benothing2 小时前
Linux文本排序统计命令:sort、uniq、wc、cut、tr实战
java·开发语言·算法
开发者联盟league2 小时前
c++11 使用chrono库转换时间点和字符串,计算时间点间隔
java·c++·算法
老歌老听老掉牙2 小时前
两个平面旋转平移坐标系间的坐标变换关系
python·算法·平面·旋转·平移
W.A委员会2 小时前
PID与PID整定
python·算法