KMP

首先对一个字符串,也就是长字符串的子串进行标记,标记方法如下:
例如 一个子串abcdabca,此时另j在a位置上,i在b位置上,进行标记,i和j的字符不同,则后移i,则有标记
abcdabca
0000
现在再后移i i移到a位置上,此时j仍在a位置上,所以出现了同一个字符,则令a位置为j+1=1;因此现在a的位置被标记为1;得到
abcdabca
00001
同时后移i和j,
'j  i
abcdabca
j此时在b位置上,i也在b位置上,又出现了同一个字符,则令b位置为j+1 且此时j为1所以j=2,b位置为2

abcdabca
000012
同时后移i和j,
 j  i
abcdabca
又出现同一个字符,令c位置为j+1 j=3
abcdabca
0000123
同时后移i和j,
  j  i
abcdabca
此时b与a不匹配,j就为他上一个字符的值,他上一个字符为c,所以j=0,此时回到字符串的开头a
再次比较字符串进行匹配,a和a刚好匹配,所以得到
abcdabca
00001231

所以得到方法是若不匹配j为前一个字符对应的值,再进行匹配,若仍不匹配,j再跳回前一个字符对应的值,若匹配则写入j+1。

下面是KMP的整体应用
例如 
abxabcabcaby
abcaby
000120

当上面指向x 下面指向c时,对应的不匹配,则子串向前看一个字符,b的临时变量为0,所以指向子串的头部,
a与x匹配吗? 当然不匹配,所以上面的指向后移至a,
直到
abxabcabcaby
     *  
abcaby
   *
这两个*的位置又出现了不匹配,往前看一个字符
abcaby
000120
b对应的值是2,所以指向c位置,因为a 0 b 1 c 2,
所以从c又开始匹配,直到结束。KMP例子就举到这里。另外代码如下:
  1. #include <stdio.h>  
  2. #include <string.h>  
  3.   
  4. int next[32] = {-999};  
  5.   
  6. /* 返回模式串T在母串S中第pos个字符的位置 */  
  7. /* 调试小技巧 print x = value 或 set var x = value 可以改变gdb运行时变量的值 */  
  8. int index_BM(char *S, char *T, int pos)  
  9. {  
  10.     int i;  
  11.     int j;  
  12.   
  13.     i = pos;  
  14.     j = 0;   
  15.   
  16.     while ( (i < strlen(S)) && (j < strlen(T)) )  
  17.     {  
  18.         if (S[i] == T[j])  
  19.         {  
  20.             i++;  
  21.             j++;  
  22.         }  
  23.         else  
  24.         {  
  25.             i = i - j + 1;   
  26.             j = 0;  
  27.         }  
  28.     }  
  29.   
  30.     /* 注意strlen(T)意味着j的取值范围为0 ~ (strlen(T) - 1) */  
  31.     if (strlen(T) == j)  
  32.     {  
  33.         return i - strlen(T);  
  34.     }  
  35.     else  
  36.     {  
  37.         return -1;  
  38.     }  
  39. }  
  40.   
  41. void get_next(char *T, int *next)  
  42. {  
  43.     int k = -1;  
  44.     int j = 0;  
  45.   
  46.     next[j] = k;  
  47.   
  48.     while (j < strlen(T))  
  49.     {  
  50.         if ( (k == -1) || (T[j] == T[k]) ) //注意等号是==,而不是=  
  51.         {  
  52.             ++k; // 注意是先加后使用  
  53.             ++j;  
  54.             next[j] = k;  
  55.         }  
  56.         else  
  57.         {  
  58.             k = next[k];   
  59.         }  
  60.     }  
  61. }  
  62.   
  63. int index_KMP(char *S, char *T, int pos)  
  64. {  
  65.     int i;  
  66.     int j;  
  67.   
  68.     i = pos;  
  69.     j = 0;   
  70.   
  71.     while ( (i < strlen(S)) && (j < strlen(T)) )  
  72.     {  
  73.         /* j = -1 表示next[0], 说明失配处在模式串T的第0个字符。所以这里特殊处理,然后令i+1和j+1。*/  
  74.         if ( (j == -1)  || S[i] == T[j])  
  75.         {  
  76.             i++;  
  77.             j++;  
  78.         }  
  79.         else  
  80.         {  
  81.             j = next[j];  
  82.         }  
  83.     }  
  84.   
  85.     if (strlen(T) == j)  
  86.     {  
  87.         return i - strlen(T);  
  88.     }  
  89.     else  
  90.     {  
  91.         return -1;  
  92.     }  
  93. }  
  94.   
  95. void print_next(int next[], int n)  
  96. {  
  97.    int i;  
  98.   
  99.    for (i = 0; i < n; i++)   
  100.    {  
  101.        printf("next[%d] = %d\n", i, next[i]);  
  102.    }  
  103. }  
  104.   
  105. int main(void)  
  106. {  
  107.     char *s = "ababcabcacbab";  
  108.     char *t = "abcac";  
  109.     int pos = 0;  
  110.     int index;  
  111.   
  112.     printf("================ BM ==============\n");  
  113.     index = index_BM(s, t, pos);  
  114.     printf("index = %d\n", index);  
  115.   
  116.     printf("================ KMP ==============\n");  
  117.     get_next(t, next);  
  118.     print_next(next, strlen(t));  
  119.   
  120.     index = index_KMP(s, t, pos);  
  121.     printf("index = %d\n", index);  
  122. }  




//优化过后的next 数组求法  
void GetNextval(char* p, int next[])  
{  
    int pLen = strlen(p);  
    next[0] = -1;  
    int k = -1;  
    int j = 0;  
    while (j < pLen - 1)  
    {  
        //p[k]表示前缀,p[j]表示后缀    
        if (k == -1 || p[j] == p[k])  
        {  
            ++j;  
            ++k;  
            //较之前next数组求法,改动在下面4行  
            if (p[j] != p[k])  
                next[j] = k;   //之前只有这一行  
            else  
                //因为不能出现p[j] = p[ next[j ]],所以当出现时需要继续递归,k = next[k] = next[next[k]]  
                next[j] = next[k];  
        }  
        else  
        {  
            k = next[k];  
        }  
    }  
}  

int KmpSearch(char* s, char* p)  
{  
    int i = 0;  
    int j = 0;  
    int sLen = strlen(s);  
    int pLen = strlen(p);  
    while (i < sLen && j < pLen)  
    {  
        //①如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++      
        if (j == -1 || s[i] == p[j])  
        {  
            i++;  
            j++;  
        }  
        else  
        {  
            //②如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]      
            //next[j]即为j所对应的next值        
            j = next[j];  
        }  
    }  
    if (j == pLen)  
        return i - j;  
    else  
        return -1;  
}  





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值