KMP算法的思想

来源:互联网 发布:c语言最大水仙花数程序 编辑:程序博客网 时间:2024/05/13 00:39

在计算机中,字符串的搜索很重要。昨天突然想起KMP算法,找了书复习了一下。把具体的思想写下来和大家共享。为什么会出现KMP算法,因为一般的字符串匹配可能会比较浪费时间。现在讲的是速率。例如:主串是:ababcabcacbab,有个子串:abcac,一般的匹配是一个一个比较,如果不等,子串从头开始,而主串则跳到开始比较的第一个字符的下一个字符。第一次主串的ab和子串的ab相等,但到第三个就不等了。这时主串跳到开始比较的下个字符,则是a后的从b开始。而子串从头开始则从a开始。这样比较浪费时间。

KMP算法的作法:不像一般匹配,当我们失配时,主串保持失配时的位置不变,而子串跳到前面一个适合的位置K(不用跳到第一个)。这时,问题就在这样确定新位置K了。

所以我们可以把子串先做预处理。KMP依靠两条重要的理论:s表示主串。p表示子串。‘i’表示失配时主串的位置,‘j’表示失配时子串的位置,例如第一次‘j’为3。k表示子串失配后应该开始的位置,而不是每次都从开头重新开始。 公式(‘括号()里的字母表示下标,例如P(j-k+1):下标是j-k+1’) (可以参考严蔚敏数据结构P81)

(1)P(j-k+1)P(j-k+2).....P(j-1) = S(i-k+1)S(j-k+2)....S(i-1)      //已经匹配可得出的条件i , j是主、子串失配的位置

  (2)  P(1)P(2)...P(k-1) = S(i-k+1)S(i-k+2)...S(i-1)   //这条是我们要求在k位置开始匹配要满足的条件

由(1)(2)可得==>  P(j-k+1)P(j-k+2).....P(j-1)  =  P(1)P(2)...P(k-1)   //很关键,我们可以看出求下个重新匹配的位置 k 原来是和“主串”没关系的。这个很重要! 

KMP算法中核心就是把“子串”预处理下,就是令next【j】= k; 就是说我们用个next数组来装子串每一个失配 “j” 要跳到新位置 “k”的数组,前面说过,其实子串失配后应该从新开始的位置和主串没联系的。只要子串不变,换个别主串next【j】还是一样。

(1) 当 j =1时。也就是第一个就失配了。则 next[ j ] = 0;

 (2)当 满足P(j-k+1)P(j-k+2).....P(j-1)  =  P(1)P(2)...P(k-1),求最大的K 作为 next【 j 】 = K;

(3)其他情况 next[ j ] = 1;

具体怎么求这个有点难。可以参考书籍,书上讲了比较多。下面我只是写出来。理解还要花时间去看详细资料。大家主要要知道这种预处理的思想可以提高效率就OK。

/////求next【】的函数
void Get_next(char T[], int next[])    // 这里T[]是子串,而且T[ 0 ] 是放着字符串的长度
{
      int i =1, j = 0;
      next[1] = 0;
     while (i < T[0])      ///// T[ 0 ] 是放着字符串的长度
     {
          if (j == 0 || T[i] == T[j])
          {            ++i; ++j;
                next[i] = j;
            } // end if 
         else
          {   j = next[j];  }
      } // end while
} // end Get_next()

 

/////    “kmp”的函数。返回的是子串在主串匹配到的位置
int Index_KMP(char S[], char T[], int next[])    ///S是主串,T是子串
{
     int i = 1, j = 1;
     while (i <= S[0] && j <= T[0])   /// S[0 ]、T[ 0 ]分别是主串和子串的长度
     {
          if (j == 0 || S[i] == T[j])
          {   ++i;

               ++j;
            }

           else {   j = next[ j ]; }
        }   /// end while
     if (j > T[0])   //如果j > T[0] 说明在S找得到子串T
     {
         return   i - T[0];         //这时 i 是主串和子串匹配成功最后的的位置,还要减去子串的长度,才是子串在主串 匹配成功的起始位置
      }

      else return 0;
}

 

我这里讲的不是很详细。呵呵,只是把主要的思想说出来,理解可能还要花时间。我自己也想了很久。希望大家有所收获~

原创粉丝点击