KMP算法两个扩展算法

学习笔记:http://blog.csdn.net/v_july_v/article/details/7041827

BM算法:

    KMP的匹配是从模式串的开头开始匹配的,而1977年1977年,德克萨斯大学的Robert S. Boyer教授和J Strother Moore教授发明了一种新的字符串匹配算法:Boyer-Moore算法,简称BM算法。该算法从模式串的尾部开始匹配,且拥有在最坏情况下O(N)的时间复杂度。在实践中,比KMP算法的实际效能高。

    BM算法定义了两个规则:

      1、坏字符规则:当文本串中的某个字符跟模式串中的某个字符不匹配时,称文本串中的这个失配字符为坏字符,此时模式串需要向右移动,移动的位数=坏字符在模式中的位置-坏字符在模式串中最右出现的位置。此外,如果坏字符不包含在模式串中,则最右出现位置为-1。

      2、好后缀规则:当字符失配时,后移的位数=好后缀在模式串中的位置-好后缀在模式串上一次出现的位置,如果好后缀在模式串中没有再次出现,则为-1。

    下面举例说明BM算法。例如,给定文本串“HERE IS A SIMPLE EXAMPLE”,和模式串“EXAMPLE”,现在要查找模式串是否在文本串中,如果存在,返回模式串在文本串中的位置。

    1、首先,文本串和模式串的头部对齐,从尾部开始比较。S与E不匹配。这时,S被称为坏字符,即不匹配字符,它对应着模式串的第6位。且S不包含在模式串EXAMPLE中(相当于最右出现的位置为-1),这意味着可以把模式串向右移动6-(-1)=7位,从而直接移动到S的后一位。

      

    2、依然从尾部开始比较,发现P与E不匹配,所以P是坏字符。但是P包含在模式串EXAMPLE之中。因为P这个坏字符对应着模式串的第6位(从0开始编号),且在模式串的最右出现位置为4,所以,模式串后移动6-4=2位,两个P对齐。

      

      

    3、依次从P位置向前比较,得到MPLE匹配,称为好后缀,也就是所有尾部匹配的字符串。注意:MPLE、PLE、LE、E都是好后缀。

      

    4、发现I与A不匹配:I是坏字符。如果根据坏字符规则,此时模式串应该向后移动2-(-1)=3位。问题是,有没有更忧 的移法?

      

       

    5、更优的移动法是利用好后缀规则:当字符失配时,后移位数=好后缀在模式串的位置-好后缀在模式串中上一次出现的位置,且如果好后缀在模式串中没有再次出现,则为-1。

      所有的好后缀(MPLE、PLE、LE、E)之中,只有E在EXAMPLE的头部出现,所以后移动的位数为6-0=6位。

      可以看出,坏字符规则只能移动3位,好后缀规则可以移动6位。每次后移动这两个规则的最大值。这两个规则的移动位数,只与模式串有关,与原文本串无关。

        

    6、继续从尾部开始比较,P与E不匹配,因此P是坏字符,根据坏字符规则,后移动6-4=2位。因为是最后一位失配,没有好后缀。

        

    可以看出,BM算法不仅效率高,而且构思巧妙,容易理解。

Sunday算法

    KMP算法和BM算法,这两个算法在最坏情况下都具有线性查找时间。实际上,KMP算法并不比最简单的c库函数strstr快多少,而BM算法通常比KMP算法快,但BM算法也不是现有字符串查找算法中最快的算法,下面介绍一种比BM算法更快的字符串查找算法即Sunday算法。

    Sunday算法和BM算法的思想及其相似:

      但,Sunday算法从前往后匹配,在匹配失败时关注的是文本串中参加匹配的最末字符的下一位字符。

        如果,该字符没有在模式串中出现,则直接跳过,即移动的位数=匹配串长度+1;

        否则,其移动的位数=模式串最右端的该字符到末尾的距离+1。

        

 1 public int Sunday()
 2     {
 3         while(i<SS.length && j<PP.length)
 4         {
 5             if(SS[i]==PP[j])
 6             {
 7                 i++;
 8                 j++;
 9             }
10             else 
11             {
12                 int k = PP.length-1;
13                 while(k>=0)
14                 {
15                     if(SS[i+PP.length+1]!=PP[k])
16                     {
17                         k--;
18                     }
19                     else
20                     {
21                         
22                     }
23                 }
24                 i = PP.length - (k+1)+1;
25                 j = 0;    
26             }            
27         }
28         
29         if(j==PP.length)
30         {
31             return i-j;
32         }
33         else {
34             return -1;
35         }
36     }

    下面举例子说明Sunday算法。假定现在要在文本串“substring searching algorithm”中查找模式串search。

    1、开始将模式串与文本串左边对齐:

      substring searching algorithm
      search
      ^

    2、结果发现在第2个两个字符处不匹配,不匹配时关注的文本串中参加匹配的最末位字符的下一个字符,即标粗的字符i,因为search中并不存在i,所以模式串直接跳过一大片,向右移动的位数=匹配串长度+1=6+1=7,从i之后的字符开始下一步匹配,如下:

     substring searching algorithm
         search
         ^

    3、结果第一个字符就不匹配,再看文本串中参加匹配的最末位字符的下一位字符,即加粗的r,它出现在模式串中的倒数第3位,于是模式串向右移动3位(r到模式串末尾的距离+1=3),使得两个r对齐,如下:

      substring searching algorithm
             search
              ^

    4、匹配成功

      Sunday算法每一次移动量都比较大,效率很高。

 

 

      

posted @ 2014-08-13 13:46  问路书童  阅读(273)  评论(0编辑  收藏  举报