zoukankan      html  css  js  c++  java
  • 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算法每一次移动量都比较大,效率很高。

          

  • 相关阅读:
    LeetCode_1.Two Sum
    F#周报2018年第48期
    使用Kdenlive为视频加入马赛克特效
    网络安全从入门到精通(第一章)前言篇
    hdu 5023 线段树染色问题
    poj 2528 线段树离散化+染色
    字符Hash初步
    经典二分:秦腾与教学评估
    国王游戏
    Trie:hdu 4825、1251、1247、Poj 3764
  • 原文地址:https://www.cnblogs.com/Jiaoxia/p/3908450.html
Copyright © 2011-2022 走看看