Knuth-Morris-Pratt(KMP)串匹配算法(C & assembly)

Knuth-Morris-Pratt(缩写KMP)串匹配算法是一个基本的串操作算法,在各种含有串操作的程序中广泛使用。
KMP匹配的最大优点在于——主串无需回溯,故可以用于数据流的匹配,如可顺序读入文件的过程中实现匹配,同时它也是各种匹配算法中速度最快的。

此处给出了算法的C代码。另外,还写了一段汇编优化的参考代码,虽无太大用处但仍可作为汇编优化的参考。程序的编写参考了 清华版 严蔚敏吴伟民著的《数据结构(C 语言版)》

 

  1. #define _USEASM_
  2. //求模式串的Next数组
  3. // p: 模式串
  4. // lp: 模式串长度
  5. inline int * getNext(const char * p, int lp=-1)
  6. {
  7.     if(lp==-1)
  8.         lp=(int)strlen(p);
  9.     //前一个模式串的Next数组
  10.     static int * next=NULL;
  11.     //如果有数据先释放内存
  12.     if(next) delete[] next;
  13.     //为Next数组分配存储空间
  14.     next=new int[lp];
  15.     //计算模式串
  16.     next[0]=-1;
  17.     int i=0; int j=-1;
  18.     while(i<lp-1)
  19.     {
  20.         if(j==-1||p==p[j])
  21.         {
  22.             i++; j++;
  23.             next=j;
  24.         }
  25.         else
  26.             j=next[j];
  27.     }
  28.     return next;
  29. }
  30. //Knuth-Morris-Pratt模式匹配算法
  31. // s: 源串
  32. // p: 模式串
  33. int instr(const char * s, const char * p)
  34. {
  35.     int ls=(int)strlen(s);
  36.     int lp=(int)strlen(p);
  37.     int * next=getNext(p,lp);
  38. #ifndef _USEASM_
  39.     int i=0; int j=0;
  40.     while(i<ls&&j<lp)
  41.     {
  42.         if(s==p[j])
  43.         { i++; j++; }
  44.         else
  45.         {
  46.             j=next[j];
  47.             if(j==-1) { i++; j++; }
  48.         }
  49.     }
  50.     if(i<ls)
  51.         return (i-j);
  52.     else
  53.         return -1;
  54. #else
  55.     _asm
  56.     {
  57.         push edi
  58.         push esi
  59.         push ebx
  60.         push ecx
  61.         push edx
  62.         mov edi, dword ptr[s]
  63.         mov esi, dword ptr[p]
  64.         mov edx, dword ptr[next]
  65.         xor ebx, ebx
  66.         xor ecx, ecx
  67.         _While_:
  68.             cmp ebx, dword ptr[ls]
  69.             jge _EndWhile_  ;大于等于转移
  70.             cmp ecx, dword ptr[lp]
  71.             jge _EndWhile_  ;大于等于转移
  72.             _If_:
  73.                 mov ah, byte ptr[edi+ebx]
  74.                 mov al, byte ptr[esi+ecx]
  75.                 cmp ah,al
  76.                 jnz _Else_
  77.                 ;_If_
  78.                 inc ebx
  79.                 inc ecx
  80.                 jmp _EndIf_
  81.             _Else_:
  82.                 shl ecx, 2
  83.                 mov ecx, dword ptr[edx+ecx]
  84.                 cmp ecx, -1
  85.                 jnz _EndIf_
  86.                     inc ebx
  87.                     inc ecx
  88.             _EndIf_:
  89.             jmp _While_
  90.         _EndWhile_:
  91.         _If2_:
  92.             cmp ebx, dword ptr[ls]
  93.             jge _Else2_
  94.             mov eax, ebx
  95.             sub eax, ecx
  96.             jmp _EndIf2_
  97.         _Else2_:
  98.             mov eax, -1
  99.         _EndIf2_:
  100.         pop edx
  101.         pop ecx
  102.         pop ebx
  103.         pop esi
  104.         pop edi
  105.     }
  106. #endif
  107. }
     (原创文章,转载时请注明本文网址)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
匹配是指在一个文本中查找另一个模式的过程。常用的匹配算法有Naïve算法、Rabin-Karp算法Knuth-Morris-Pratt算法。 1. Naïve算法 Naïve算法是最简单的匹配算法,也称为暴力匹配算法。它的思路是从文本的第一个字符开始,依次比较文本中的每个字符是否与模式中的字符相等。若不相等,则继续向后比较;若相等,则比较下一个字符,直到找到完全匹配的子或文本匹配完为止。 Naïve算法的时间复杂度是O(mn),其中m和n分别是模式和文本的长度。当模式和文本长度相等时,最坏情况下时间复杂度达到O(n^2)。 2. Rabin-Karp算法 Rabin-Karp算法是一种基于哈希值的匹配算法。它的思路是先将模式和文本都转换为哈希值,然后比较它们的哈希值是否相等。如果哈希值相等,则再逐个比较模式和文本中的字符是否相等。这种方法可以有效地减少比较次数,提高匹配效率。 Rabin-Karp算法的时间复杂度是O(m+n),其中m和n分别是模式和文本的长度。但是,由于哈希函数的不完全性和哈希冲突的存在,Rabin-Karp算法在某些情况下可能会出现误判。 3. Knuth-Morris-Pratt算法 Knuth-Morris-Pratt算法是一种基于前缀函数的匹配算法。它的思路是先计算出模式的前缀函数,然后利用前缀函数的信息来跳过已经匹配过的部分,减少比较次数。 具体来说,KMP算法匹配过程中维护一个指针i和一个指针j,其中i指向文本中当前匹配的位置,j指向模式中当前匹配的位置。如果当前字符匹配成功,则i和j同时向后移动一位;如果匹配失败,则通过前缀函数计算出j需要跳转到的位置,使得前j-1个字符与文本中的对应字符已经匹配成功,然后将j指向这个位置,i不变,继续比较下一个字符。 KMP算法的时间复杂度是O(m+n),其中m和n分别是模式和文本的长度。由于利用了前缀函数的信息,KMP算法可以在最坏情况下达到O(n)的时间复杂度,比Naïve算法和Rabin-Karp算法更加高效。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值