移山之道

关注软件开发技术和管理的社区网站

欢迎光临 移山之道 登录 | 注册 | 帮助
in 搜索

Silver

最短摘要生成与多模式匹配(三)

 

Boyer-Moore算法——“坏后缀规则”?

如前贴所述,BM算法的“好后缀规则”实际上有两种情况:“中缀”和“前缀”。

“前缀”没啥问题,但是我发现“中缀”往往会出现“跳转以后朝向注定的失败匹配”,如下图所示:

image

如上图,在第6位X处发生了miss match,BM算法会跳转到3位,也就是将pat挪到如上表第三行的样子,再从11位开始比较,假设11~7都匹配成功了,但是X!=B,第6位是注定失败的。

那么可否将“中缀跳表”独立出来,匹配过程中判断”好后缀”加上它的前导字符构成的子串是否在pat中存在?如果不存在就是个“坏后缀”。

例如:上图中的“XXY”实际上是“坏后缀”,而不是“好后缀”,因为在pat中根本不存在这样的子串。

如何考虑“坏后缀规则”?

如果要实现这个规则,需要注意两个问题。

如下图,和前面一样,假设在倒数第三位X处发生了miss match,可以跳转到两个位置(如箭头所示),但是有一个跳转是重复的,A=A。

image

因此可以看出,如果要独立“中缀跳表”,需要考虑两个问题:

  1. 某位置的中缀跳转可能不止一个;
  2. 跳转中可能存在重复。如果出现重复,需要取最右边的那个。

很容易想到,满足这两个需求,用个哈希表恰好。

一种实现方法

将(二)贴中的计算中缀跳表的地方用一个函数AddInfixJump(i, j);代替,这个函数如下:

/// <summary>
/// 中缀跳表
/// </summary>
static Dictionary<char, int>[] iJumps;
static void AddInfixJump(int i, int j)
{
    if (j < m - 1)//最后一位采用坏字符移动,这里不需要
    {
        if (iJumps[ j ] == null) iJumps[ j ] = new Dictionary<char, int>();
        //添加中缀跳 能保证从小到大
        if (!iJumps[ j ].ContainsKey(pat[ i ])) iJumps[ j ].Add(pat[ i ], i);
    }
}

这样去计算中缀跳表,能够保证没有重复,并且右边的跳转肯定是先计算的,所以保留的也是最右边的。

然后在搜索过程中,如果在pat倒数第1位以前发生了miss match(也就是不用“坏字符规则”)的时候,先设置跳转为原来的那个表(比原来少了中缀跳转而已),然后再看看是否有好的“中缀”:

shift = mJumps[ j ];//设置为前缀和坏后缀混合跳转
 
if (iJumps[ j ] != null &&//存在中缀 
    iJumps[ j ].ContainsKey(text[ i ]))//且跳转以后匹配text[ i ]
    shift = m - 1 - iJumps[ j ][text[ i ]];//设置中缀跳 (m-1-j + j-k)

这样能够避免上面出现“注定的失败”了。

实验结果

通过实验我发现,这样改进以后,在随机字符串和英文文章的匹配中,比较次数能够降低10%~30%,但是总体性能提高却不明显。我估计性能肯定是损失在C#的泛型字典Dictionary<>上面了,“坏后缀”的思路应该很好,但是可能需要别的实现方法:比如字符集小的话可以用数组,或者别的语言实现。有人想到好方法麻烦告诉我:)

后记

这和我一直以来的编程经验是相反的:“一般来说,不应该先考虑太细节的优化,算法思想的优化是最重要的”;但是在字符匹配的程序中不完全是这样,字符比较的消耗很小,稍微复杂的逻辑和数据结构都会损失性能,所以凡事都有例外。

有些细节优化却能够提升性能,例如,原版的BM搜索过程是这样的:

var shift = 0;
var k = (int)text[ i ];
if (k < cJumps.Count) shift = cJumps[ k ];
else shift = m;
i += Math.Max(shift, mJumps[ j ]);

贴(二)中,我将其改为:

if (m - j == 1)//末位不匹配
 {
     var k = (int)text[ i ];
     if (k < cJumps.Count) i += cJumps[ k ];
     else i += m;
 }
 else i += mJumps[ j ];

实际上就是当匹配超过1个字符时候,不用去计算“坏字符跳”。这样小改动一点,在随机字符和英文测试中,性能都提高了10%左右。

当然要说明的是,MB算法总体性能相比最原始的BruteForce算法还是有大幅提高的,pat越长越明显。

已发表 2010年1月4日 17:21 作者 silver
归档在:

评论

 

机械唯物主义 说:

请问平时在哪里交流?

我们有个社区:http://groups.google.com/group/pongba

不知道你是否感兴趣?

七月 20, 2010 17:29
 

silver 说:

不好意思,一直忙于一些非技术活

最近打算得重整旗鼓了...

谢谢您的邀请,不过打不开

八月 17, 2010 20:15
注册后即可发表评论

About silver

有6 年多的项目开发经验,先后设计、开发了多个仿真系统、辅助决策系统(约三百万行代码)。负责或参与多个大型项目(如国家863项目)。 精益求精,力求完美,追求用最自然、简单、易读的代码去实现复杂的功能。 个人网站:http://eil.stanford.edu/pengao/
Powered by Community Server (Personal Edition), by Telligent Systems
访问计数:     京ICP备06016978号
王屋村村民除了看yishan.cc, 还浏览下列网站.