Eugene W. Myers 在他1986年发表于"Algorithmica"的论文"An O(ND) Difference Algorithm and Its Variations"中描述了一种用于处理diff的基础贪婪算法. 在他的论文中, 还对这种算法进行了扩展"Linear Space Refinement".

定义文件A和文件B, 算法会读取两个文件的输入, 假设B为新版本, 算法会生成一段Shortest Edit Script (SES, 最短编辑脚本) 用于将A转换为B . SES只包含两种命令: 从A中删除, 以及在B中插入
寻找SES 等价于寻找 Longest Common Subsequence ( LCS 最长公共子序列 ), LCS是两个文件中去掉一些字符后, 所产生的共有的最长的字符串序列. 注意, 这与 Longest Common Substring (最长公共字符串)不同, 后者是必须连续的.

两个文件中, 可能存在多个LCS, 例如ABC和ACB, 存在两个LCS "AB"和"AC", 在这里分别对应了一个SES. 这个算法在存在多个SES时, 仅返回第一个找到的SES.

算法的运作是依赖于A和B文件构成的有向编辑图, 图中A为X轴, B为Y轴, 假定A和B的长度分别为m, n, 每个坐标代表了各自字符串中的一个字符. 在图中沿X轴前进代表删除A中的字符, 沿Y轴前进代表插入B中的字符. 在横坐标于纵坐标字符相同的地方, 会有一条对角线连接左上与右下两点, 表示不需任何编辑, 等价于路径长度为0. 算法的目标, 就是寻找到一个从坐标(0, 0)到(m, n)的最短路径

算法在比较中, 定义了以下变量

k: 左上至右下的对角线, 以(0,0)对应的对角线k=0, 左侧为-1, -2, ... 右侧为1, 2, ...
d: 路径长度
x, y: 坐标

snake: 代表了一步操作及其后面跟随的对角线移动

Source: https://www.codeproject.com/Articles/42279/Investigating-Myers-diff-algorithm-Part-2-of-2

Java代码

public static void main(String[] args) {
String a = "ABCABBACDAB";
String b = "CBABACDAA";
char[] aa = a.toCharArray();
char[] bb = b.toCharArray();
int max = aa.length + bb.length;
int[] v = new int[max * 2];
List<Snake> snakes = new ArrayList<>(); for (int d = 0; d <= aa.length + bb.length; d++) {
System.out.println("D:" + d);
for (int k = -d; k <= d; k += 2) {
System.out.print("k:" + k);
// down or right?
boolean down = (k == -d || (k != d && v[k - 1 + max] < v[k + 1 + max]));
int kPrev = down ? k + 1 : k - 1; // start point
int xStart = v[kPrev + max];
int yStart = xStart - kPrev; // mid point
int xMid = down ? xStart : xStart + 1;
int yMid = xMid - k; // end point
int xEnd = xMid;
int yEnd = yMid; // follow diagonal
int snake = 0;
while (xEnd < aa.length && yEnd < bb.length && aa[xEnd] == bb[yEnd]) {
xEnd++;
yEnd++;
snake++;
}
// save end point
v[k + max] = xEnd;
// record a snake
snakes.add(0, new Snake(xStart, yStart, xEnd, yEnd));
System.out.print(", start:("+xStart+","+yStart+"), mid:("+xMid+","+yMid+"), end:("+xEnd+","+yEnd + ")\n");
// check for solution
if (xEnd >= aa.length && yEnd >= bb.length) {
/* solution has been found */
System.out.println("found");
/* print the snakes */
Snake current = snakes.get(0);
System.out.println(String.format("(%2d, %2d)<-(%2d, %2d)", current.getxEnd(), current.getyEnd(), current.getxStart(), current.getyStart()));
for (int i = 1; i < snakes.size(); i++) {
Snake tmp = snakes.get(i);
if (tmp.getxEnd() == current.getxStart()
&& tmp.getyEnd() == current.getyStart()) {
current = tmp;
System.out.println(String.format("(%2d, %2d)<-(%2d, %2d)", current.getxEnd(), current.getyEnd(), current.getxStart(), current.getyStart()));
if (current.getxStart() == 0 && current.getyStart() == 0) {
break;
}
}
}
return;
}
}
}
} public static class Snake {
private int xStart;
private int yStart;
private int xEnd;
private int yEnd; public Snake(int xStart, int yStart, int xEnd, int yEnd) {
this.xStart = xStart;
this.yStart = yStart;
this.xEnd = xEnd;
this.yEnd = yEnd;
} public int getxStart() {
return xStart;
} public void setxStart(int xStart) {
this.xStart = xStart;
} public int getyStart() {
return yStart;
} public void setyStart(int yStart) {
this.yStart = yStart;
} public int getxEnd() {
return xEnd;
} public void setxEnd(int xEnd) {
this.xEnd = xEnd;
} public int getyEnd() {
return yEnd;
} public void setyEnd(int yEnd) {
this.yEnd = yEnd;
}
}

运行结果

D:0
k:0, start:(0,-1), mid:(0,0), end:(0,0)
D:1
k:-1, start:(0,0), mid:(0,1), end:(0,1)
k:1, start:(0,0), mid:(1,0), end:(1,0)
D:2
k:-2, start:(0,1), mid:(0,2), end:(2,4)
k:0, start:(1,0), mid:(1,1), end:(2,2)
k:2, start:(1,0), mid:(2,0), end:(3,1)
D:3
k:-3, start:(2,4), mid:(2,5), end:(3,6)
k:-1, start:(2,4), mid:(3,4), end:(4,5)
k:1, start:(3,1), mid:(3,2), end:(5,4)
k:3, start:(3,1), mid:(4,1), end:(5,2)
D:4
k:-4, start:(3,6), mid:(3,7), end:(4,8)
k:-2, start:(4,5), mid:(4,6), end:(4,6)
k:0, start:(5,4), mid:(5,5), end:(5,5)
k:2, start:(5,4), mid:(6,4), end:(10,8)
k:4, start:(5,2), mid:(6,2), end:(7,3)
D:5
k:-5, start:(4,8), mid:(4,9), end:(4,9)
k:-3, start:(4,8), mid:(5,8), end:(5,8)
k:-1, start:(5,5), mid:(5,6), end:(5,6)
k:1, start:(10,8), mid:(10,9), end:(10,9)
k:3, start:(10,8), mid:(11,8), end:(11,8)
k:5, start:(7,3), mid:(8,3), end:(8,3)
D:6
k:-6, start:(4,9), mid:(4,10), end:(4,10)
k:-4, start:(5,8), mid:(5,9), end:(5,9)
k:-2, start:(5,8), mid:(6,8), end:(7,9)
k:0, start:(10,9), mid:(10,10), end:(10,10)
k:2, start:(11,8), mid:(11,9), end:(11,9)
found
(11, 9)<-(11, 8)
(11, 8)<-(10, 8)
(10, 8)<-( 5, 4)
( 5, 4)<-( 3, 1)
( 3, 1)<-( 1, 0)
( 1, 0)<-( 0, 0)

动态规划处理diff算法 Myers Diff (正向)的更多相关文章

  1. 文本diff算法Patience Diff

    一般在使用 Myers diff算法及其变体时, 对于下面这种例子工作不是很好, 让变化不易阅读, 并且容易导致合并冲突 void Chunk_copy(Chunk *src, size_t src_ ...

  2. React Diff算法一览

    前言 diff算法一直是React系统最核心的部分,并且由于演化自传统diff,使得比较方式从O(n^3)降级到O(n),然后又改成了链表方式,可谓是变化万千. 传统Diff算法 传统diff算法需要 ...

  3. 【React自制全家桶】二、分析React的虚拟DOM和Diff算法

    一.React如何更新DOM内容: 1.  获取state 数据 2.  获取JSX模版 3.  通过数据 +模版结合,生成真实的DOM, 来显示,以下行代码为例(简称代码1) <div id= ...

  4. 深入理解React:diff 算法

    目录 序言 React 的核心思想 传统 diff 算法 React diff 两个假设 三个策略 diff 具体优化 tree diff component diff element diff 小结 ...

  5. 虚拟DOM与diff算法

    虚拟DOM与diff算法 虚拟DOM 在DOM操作中哪怕我们的数据,发生了一丢丢的变化,也会被强制重建整预DOM树.这么做,涉及到很多元素的重绘和重排,导致性能浪费严重 只要实现按需更新页面上的元素即 ...

  6. 探究虚拟dom与diff算法

    一.虚拟DOM (1)什么是虚拟DOM? vdom可以看作是一个使用javascript模拟了DOM结构的树形结构,这个树结构包含整个DOM结构的信息,如下图:   可见左边的DOM结构,不论是标签名 ...

  7. diff算法深入一下?

    文章转自豆皮范儿-diff算法深入一下 一.前言 有同学问:能否详细说一下 diff 算法. 简单说:diff 算法是一种优化手段,将前后两个模块进行差异化比较,修补(更新)差异的过程叫做 patch ...

  8. react diff算法浅析

    diff算法作为Virtual DOM的加速器,其算法的改进优化是React整个界面渲染的基础和性能的保障,同时也是React源码中最神秘的,最不可思议的部分 1.传统diff算法计算一棵树形结构转换 ...

  9. 深入理解react中的虚拟DOM、diff算法

    文章结构: React中的虚拟DOM是什么? 虚拟DOM的简单实现(diff算法) 虚拟DOM的内部工作原理 React中的虚拟DOM与Vue中的虚拟DOM比较 React中的虚拟DOM是什么?   ...

随机推荐

  1. 【UOJ Round #3】

    枚举/二分 C题太神窝看不懂…… 核聚变反应强度 QwQ很容易发现次小的公约数一定是gcd的一个约数,然后……我就傻逼地去每次算出a[1],a[i]的gcd,然后枚举约数……这复杂度……哦呵呵... ...

  2. POJ 1719 Shooting Contest(二分图匹配)

    POJ 1719 Shooting Contest id=1719" target="_blank" style="">题目链接 题意:给定一个 ...

  3. Mockito 的使用

    转自:Mockito 中文文档 ( 2.0.26 beta ) 转自:手把手教你 Mockito 的使用 参数匹配器 Argument Matcher(参数匹配器) Mockito通过equals() ...

  4. jQuery EasyUI Datagrid性能优化专题(转)

    jQuery  EasyUI的Datagrid组件功能算是很强大了,不过性能确实不怎么乐观,而对于性能问题,网络上几乎也找不到相关的优化资料,所谓的牛人们可能 都望而却步了.本博客以后会带着分析Dat ...

  5. 【算法】Java-Redis-Hash算法对比-参考资料

    Java-Redis-Hash算法对比-参考资料 redis java map 红黑树_百度搜索 java使用redis缓存(String,bean,list,map) - CSDN博客 redis ...

  6. python实现itemCF and userCF

    http://my.oschina.net/zhangjiawen/blog/185625 1基于用户的协同过滤算法: 基于用户的协同过滤算法是推荐系统中最古老的的算法,可以说是这个算法的诞生标志了推 ...

  7. Spearman(斯皮尔曼) 等级相关

    Spearman相关系数又称秩相关系数,是利用两变量的秩次大小作线性相关分析,对原始变量的分布不作要求,属于非参数统计方法,适用范围要广些.对于服从Pearson相关系数的数据亦可计算Spearman ...

  8. JPA(六):映射关联关系------映射单向一对多的关联关系

    映射单向一对多的关联关系 新建项目项目请参考<JPA(二):HellWord工程>,基于上一章讲解的<JPA(五):映射关联关系------映射单向多对一的关联关系>中的例子进 ...

  9. ElasticSearch 5.X 搜索并用高亮显示

    public List<WOSearchModel> searchOrder(OrderSearchReqVO request) throws Exception{List<WOSe ...

  10. [Angular] Communicate with Angular Elements using Inputs and Events

    In a real world scenario we obviously need to be able to communicate with an Angular Element embedde ...