【模式匹配】之 —— Sunday算法


Sunday算法思路

Sunday算法的思想和BM算法中的坏字符思想非常类似。

差别只是在于Sunday算法在失配之后,是取目标串中当前和模式串对应的部分后面一个位置的字符来做坏字符匹配。
如下图:
下标数:01234567890
目标串:abcdefghijk
模式串:bxcd

BM算法在b和x失配后,坏字符为b(下标1),在模式串中寻找b的位置,找到之后就对应上,移到下面位置继续匹配。
目标串:abcdefghijk
模式串: bxcd

而在sunday算法中,对于上面的匹配,发现失配后,是取目标串中和模式串对应部分后面的一个字符,也就是e,然后用e来做坏字符匹配。
e在模式串中没有,所以使用sunday算法,接下来会移动到下面的位置继续匹配。
目标串:abcdefghijk
模式串:     bxcd

从这里可以看出,Sunday算法比BM算法的位移更大,所以Sunday算法比BM算法的效率更高。但是最坏的时间复杂度仍然有o(目标串长度*模式串长度)。考虑这样的目标串:baaaabaaaabaaaabaaaa,要在里面搜索aaaaa,显然是没有匹配位置。但是如果用Sunday算法,坏字符大部分都是a,而模式串中又全部都是a,所以在大部分情况下,发现失配后模式串只能往右移动1位。而如果用改进的KMP算法,仍然是可以保证线性时间内匹配完。

另外,使用Sunday算法不需要固定地从左到右匹配或者从右到左的匹配(这是因为失配之后我们用的是目标串中后一个没有匹配过的字符), 我们可以对模式串中的字符出现的概率事先进行统计,每次都使用概率最小的字符所在的位置来进行比较,这样失配的概率会比较大,所以可以减少比较次数,加快匹配速度。
如下面的例子:
目标串:abcdefghijk
模式串:aabcc
模式串中b只出现了一次,a,c都出现了2次,所以我们可以先比较b所在的位置(只看模式串中的字符的话,b失配的概率会比较大)。

总之,Sunday算法简单易懂,思维跳出常规匹配的想法,从概率上来说,其效率在匹配随机的字符串时比其他匹配算法还要更快。

完整的Sunday算法

  1. #include <stdio.h>  
  2. #include <string.h>  
  3.   
  4. bool BadChar(const char *pattern, int nLen, int *pArray, int nArrayLen)  
  5. {  
  6.     if (nArrayLen < 256)  
  7.     {  
  8.         return false;  
  9.     }  
  10.     for (int i = 0; i < 256; i++)  
  11.     {  
  12.         pArray[i] = -1;  
  13.     }  
  14.     for (int i = 0; i < nLen; i++)  
  15.     {  
  16.         pArray[pattern[i]] = i;  
  17.     }  
  18.     return true;  
  19. }  
  20.   
  21. int SundaySearch(const char *dest, int nDLen,  
  22.                  const char *pattern, int nPLen,  
  23.                  int *pArray)  
  24. {  
  25.     if (0 == nPLen)  
  26.     {  
  27.         return -1;  
  28.     }  
  29.     for (int nBegin = 0; nBegin <= nDLen-nPLen; )  
  30.     {  
  31.         int i = nBegin, j = 0;   
  32.         for ( ;j < nPLen && i < nDLen && dest[i] == pattern[j];i++, j++);  
  33.         if (j == nPLen)  
  34.         {  
  35.             return nBegin;  
  36.         }  
  37.         if (nBegin + nPLen > nDLen)  
  38.         {  
  39.             return -1;  
  40.         }  
  41.         else  
  42.         {  
  43.             nBegin += nPLen - pArray[dest[nBegin+nPLen]];  
  44.         }  
  45.     }  
  46.     return -1;  
  47. }  
  48.   
  49. void TestSundaySearch()  
  50. {  
  51.     int         nFind;  
  52.     int         nBadArray[256]  = {0};  
  53.                                //        1         2         3         4  
  54.                                //0123456789012345678901234567890123456789012345678901234  
  55.     const char  dest[]      =   "abcxxxbaaaabaaaxbbaaabcdamno";  
  56.     const char  pattern[][40] = {  
  57.         "a",  
  58.         "ab",  
  59.         "abc",  
  60.         "abcd",  
  61.         "x",  
  62.         "xx",  
  63.         "xxx",  
  64.         "ax",  
  65.         "axb",  
  66.         "xb",  
  67.         "b",  
  68.         "m",  
  69.         "mn",  
  70.         "mno",  
  71.         "no",  
  72.         "o",  
  73.         "",  
  74.         "aaabaaaab",  
  75.         "baaaabaaa",  
  76.         "aabaaaxbbaaabcd",  
  77.         "abcxxxbaaaabaaaxbbaaabcdamno",  
  78.     };  
  79.   
  80.     for (int i = 0; i < sizeof(pattern)/sizeof(pattern[0]); i++)  
  81.     {  
  82.         BadChar(pattern[i], strlen(pattern[i]), nBadArray, 256);  
  83.         nFind = SundaySearch(dest, strlen(dest), pattern[i], strlen(pattern[i]), nBadArray);  
  84.         if (-1 != nFind)  
  85.         {  
  86.             printf("Found    \"%s\" at %d \t%s\r\n", pattern[i], nFind, dest+nFind);  
  87.         }  
  88.         else  
  89.         {  
  90.             printf("Found    \"%s\" no result.\r\n", pattern[i]);  
  91.         }  
  92.   
  93.     }}  
  94.   
  95. int main(int argc, char* argv[])  
  96. {  
  97.     TestSundaySearch();  
  98.     return 0;  
  99. }  

输出结果:
  1. Found    "a" at 0       abcxxxbaaaabaaaxbbaaabcdamno  
  2. Found    "ab" at 0      abcxxxbaaaabaaaxbbaaabcdamno  
  3. Found    "abc" at 0     abcxxxbaaaabaaaxbbaaabcdamno  
  4. Found    "abcd" at 20   abcdamno  
  5. Found    "x" at 3       xxxbaaaabaaaxbbaaabcdamno  
  6. Found    "xx" at 3      xxxbaaaabaaaxbbaaabcdamno  
  7. Found    "xxx" at 3     xxxbaaaabaaaxbbaaabcdamno  
  8. Found    "ax" at 14     axbbaaabcdamno  
  9. Found    "axb" at 14    axbbaaabcdamno  
  10. Found    "xb" at 5      xbaaaabaaaxbbaaabcdamno  
  11. Found    "b" at 1       bcxxxbaaaabaaaxbbaaabcdamno  
  12. Found    "m" at 25      mno  
  13. Found    "mn" at 25     mno  
  14. Found    "mno" at 25    mno  
  15. Found    "no" at 26     no  
  16. Found    "o" at 27      o  
  17. Found    "" no result.  
  18. Found    "aaabaaaab" no result.  
  19. Found    "baaaabaaa" at 6       baaaabaaaxbbaaabcdamno  
  20. Found    "aabaaaxbbaaabcd" at 9         aabaaaxbbaaabcdamno  
  21. Found    "abcxxxbaaaabaaaxbbaaabcdamno" at 0    abcxxxbaaaabaaaxbbaaabcdamno 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值