字符串的模式匹配:Sunday 算法

Posted xlxxcc

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了字符串的模式匹配:Sunday 算法相关的知识,希望对你有一定的参考价值。

  Sunday算法是Daniel M.Sunday于1990年提出的字符串模式匹配。其核心思想是:在匹配过程中,模式串发现不匹配时,算法能跳过尽可能多的字符以进行下一步的匹配,从而提高了匹配效率。其效率在匹配随机的字符串时比其他匹配算法还要更快。Sunday算法的实现可比KMP,BM的实现容易太多。
  要理解Sunday算法,建议先阅读《字符串的模式匹配: BF算法》《字符串的模式匹配:KMP算法》 《字符串的模式匹配:BM算法 》
  时间复杂度:最差情况O(MN),最好情况O(N)

算法思想:

  在匹配过程中,先从左到右逐个字符比较,当模式串发现不匹配时,跳过尽可能多的字符以进行下一步的匹配,从而提高了匹配效率。
  模式串向后位移:字符串和模式串同时移动的长度 + 模式串的长度 - 该字符在模式串中出现的第一个位置(从右向左寻找模式串,如果寻找不到则为-1)。
  开始的时候,让字符串”T”的第一个字符T[0]和模式串”P”的第一个字符P[0]匹配,如果不匹配。以字符串出现在模式串后面的位置n,取T[n]字符,找到该字符在模式串字符的的位置k,并将模式串p[k]字符与T[n]对齐,即模式串向后位移n-k; 若在模式串中找不到T[n]字符,则将模式串p[0]与字符串T[n]对齐,模式串向后以模式串长度位移。位移后再比对P[0]和T[N], 按照上述过程依此匹配。
  下面还是看一下实际的匹配过程,道理可能讲的是不够清晰。

匹配过程:

假设有字符串和模式串如下:
字符串T: “Lessons tearned en software te”
模式串P: “software”
模式串P的长度为8。字符串T的长度为30。

1、首先字符串T和模式串P首字符对齐。如下:

Lessons tearned en software te
software

2、然后T[0]和P[0]字符匹配,也就是”L”和”s”, 这个时候不匹配;根据Sunday算法要求,以字符串出现在模式串后面的位置n,取T[n]字符,找到T[n]即T[8]字符”t”位于模式串P中从后向前查找出现的第一个位置,即模式串的P[3]。模式串向后位移:字符串和模式串同时移动的长度 + 模式串的长度 - 该字符在模式串中出现的第一个位置。 模式串移动位数 = 0 + 8 - 3 = 5位, 位移5位后T[8]与P[3]对齐后得到如下结果:

Lessons tearned en software te
     software

3、比对T[5]和P[0],也就是”n”和”s”, 这个时候不匹配,再次寻找字符串中在模式串后面的那个字符在模式串中出现的位置。也就是字符串的tearned 中的”e”,并且寻找”e”在模式串出现的位置,也就是模式串的P[7]位置。此时模式串位移 = 0 + 8 - 7 = 1位。位移后得到结果:

Lessons tearned en software te
      software

4、此时,对比T[6]和P[0],也就是”s”和”s”, 发现字符匹配。那么字符串和模式串同时向后移1位。 对比T[6+1]和P[0+1], 也就是字符串的” “和模式串的”o”,发现 再次不匹配。找到字符串在模式串后移1位T[6+1+8]的字符” “, 寻找字符”d”在模式串的位置,发现模式串中不存在d,也就是说。 模式串移动位数 = 1 + 8 - (-1) = 10, 移动结果如下:

Lessons tearned en software te
                software

5、依此类推,直到找到匹配的位置,或者到达字符串的末尾 。

再假设有字符串和模式串如下:
字符串T: “Lessonsotearned en software te”
模式串P: “software”
模式串T的长度为8。字符串T的长度为30。
其匹配过程,第1、2、3步与上诉例子的1、2、3不一样,运行后位移如下:

Lessonsotearned en software te
      software

那么如上对齐后,匹配字符串T[6]与模式串P[0], 也就是”s”和”s”, 匹配一致。那么字符串T和模式串P后移1位,匹配字符串T[6+1]与模式串P[0+1],也就是”o”和”o”, 匹配一致。那么字符串T和模式串P再次后移1位,匹配字符串T[6+1+1]与模式串P[0+1+1],也就是”t”和”f”不一致。所以模式串移动位数 = 2 + 8 - 7 = 3, 得到结果如下:

Lessonsotearned en software te
         software

直到找到匹配的位置,或者到达字符串的末尾 。

具体实现(java):

    /// <summary>
    /// 通过Sunday查找算法,查找text串中pattern字串的第一次出现的位置,没查找到返回-1
    /// </summary>
    /// <param name="text">目标(源)串</param>
    /// <param name="pattern">匹配串</param>
    /// <returns>int,返回第一次出现的索引.返回-1表示没有找到.</returns>
    public static int sundaySearch(char[] text, char[] pattern)
        int i = 0, j = 0, k;/*分别记录text索引,pattern索引还有,串匹配计数时索引*/
        int tl, pl;/*分别记录字符串text和pattern的长度*/
        int pe;/*分别记录text匹配pattern最后的索引的下一个索引*/
        int rev=-1;/*记录返回的索引值,否则无法返回*/

        /*非法情况,直接返回-1*/
        if ((text == null) || (pattern == null) || (tl = text.length) < (pl = pattern.length))
            return -1;

        while (i < tl && j < pl) 
            /* 匹配正确就仅继续匹配 */
            if (text[i] == pattern[j]) 
                ++i;
                ++j;
                continue;
            
            pe = i + pl;
            /* 匹配失败,移动i和j索引值,为下一次匹配做准备 */
            if (pe >= tl) /* 当下一次的位置已经超过text的长度时,返回-1表示没有找到 */
                return -1;
            for (k = pl - 1; k >= 0 && text[pe] != pattern[k]; --k)
                ;
            i += (pl - k);// (pl - k)表示i需要移动的步长
            rev = i;// 记录当前的索引
            j = 0;/* j重新开始 */
            // System.out.println("总移动位数:" + rev);
        
        return i <= tl ? rev : -1;
     

以上是关于字符串的模式匹配:Sunday 算法的主要内容,如果未能解决你的问题,请参考以下文章

Sunday算法模板

字符串匹配之Sunday算法

Sunday算法

模式匹配——Sunday算法

Sunday算法

Sunday算法