KMP mode matching

Source: Internet
Author: User

During development, you often encounter the need to check whether a string t exists in string S and find its first position, that is, find the substring t in string S, how do we achieve this? We can use at least three methods, the find function in cstring and string, and the string. the strstr function in H is simple and quick to use. cstring is something in MFC, string is something in the C ++ standard library, and strstr is a string in C. something in H seems that we don't have to implement the locating and searching function on our own ...... But what if I want to implement it myself? Can we simulate the string in MFC, cstring in C ++, and strstr in string. h to implement a function by ourselves? Next, let's take a look and see if it can be implemented.

1. Simple mode matching

If S = "ababcababcac", t = "abcac", find t in S; the most direct method we can think of is to compare every character in T and every character in s one by one, as shown below:

From the comparison process, we can find that after each comparison failure, I and j will be traced back; the comparison will not stop, and the time complexity is O (Mn); the algorithm is very simple, the Code is as follows:

Int bfmatcher (const char * strmain, const char * strsub) {int n = strlen (strmain); int M = strlen (strsub); Int J = 0; int I = 0; while (I <n) {While (j <M & strsub [J] = strmain [I]) {If (j = s-1) return I-j; j ++; I ++;} I = I-j + 1; // trace J = 0;} return-1 ;}


2. KMP Algorithm

Based on the above steps, we will take a closer look at Step 1 and Step 2 and find that after we fail to compare C in A and T in step 1, step 2: Compare the B in s that has been compared in step 1 with the first a in T. Through step 1, we know that the second in S is B, it is impossible to compare it with the first a in T. This step is completely redundant. The above simple method we implemented did not use the result obtained by the first comparison. What is this, if we do not learn from the experience, we should use the comparison results of the first step in the second step. If we use the comparison results, we can skip the second step, significantly saving time, the comparison between Step 1 and Step 2 should be as follows:

According to this method, we can find the t position in s in this four-step comparison, avoiding repeated backtracking of I and J, which is several times faster than the above method. But this example looks simple, but how can we implement it through programming? How can we make it general? Let's first look at how the Second Step reaches the third step:

Step 2 compare the position where I is the third character a in S at the beginning, that is, I = 2; j = 0 in T; when I = 7, when J = 4, the comparison fails. in step 3, we found that the starting position of the comparison in S is still I = 7, and the position of J in T is changed to 1, in step 2, we found that "ABCA" successfully found the location in S. We compared s [6] and t found that s [6] = T [3], at the same time, s [6] = T [0]; therefore, in step 3, S [6] and T [0] do not need to be compared, by observing "ABCA" and T [0] T [3], we can find that t [0] and T [3] are the true prefixes and suffixes of "ABCA", respectively, T [0] = T [3], does it mean that we only need to find the string T [0... Q] Can we know the starting position of J in the next comparison of T? For example, if the length of the true prefix of "ABCA" obtained in step 2 is 1, then the position of the next J comparison is 1. It can be seen that, after the comparison fails, I in S does not need to be moved, only the next J needs to be obtained, and this J only has nothing to do with S.


Let's sum up, assume that the S string length is N, the T string length is m, m <= N, and T, T [1... Q] = s [I + 1... I + q] 0 <q <m (note: in step 2 of the above example, I = 2, q = 4, here t [1... Q] indicates the elements from T [0] to T [q-1], and t [1... Q + 1]! = S [I + 1... I + q + 1]; and T [1... K] = s [I '+ 1... I '+ k] 1 <k <q I + 1 <I' <I + Q, where I '= I + q-K; then the matching test will become very simple. We can find the K value, that is, t [1... Q] is the maximum true prefix length. The value of this length is the value of the next J.

The following question is the next J after the acquisition fails, that is, how to find t [1... Q.

We can see 1 <q <m, so we need to get t [1... 1] to T [1... M] is the maximum true prefix of all strings, so you can directly obtain the length of these largest true prefix in advance into an array next [] for use.

With this next array, you can write the search function as follows:

 

int KMP_Matcher(const char* strMain,const char* strSub){if ( NULL == strMain || NULL == strSub )return -1;int n = strlen(strMain);int m = strlen(strSub);int next[MAX_STRING_LEN] = {0};GetNext(strSub,next);int q = 0;for ( int i=0 ; i<n ; i++ ){while ( q>0 && strSub[q]!=strMain[i] )q = next[q];if ( strSub[q] == strMain[i] )q = q+1;if ( q==m-1 )return i-q+1;}return -1;}

Now we only need to find a way to implement this getnext function to fill the next array:

Next [1] = 0, because T [1... 1] there is no real prefix, so we can use recursion to solve the next array. For q> 1, we suppose next [1], next [2], next [3], next [4]… The maximum true prefix length of all strings in next [q-1], so next [Q? Set next [q-1] = K, then t [1... K] is t [1... The maximum true prefix in q-1], so we assume two conditions for T [Q:

1. t [k + 1] = T [Q], so this is simple. This shows the string T [1... K] and T [1... The last digit of the Q-1] is equal. If we know next [q-1] = K, then next [Q] = k + 1.

2. t [k + 1]! = T [Q], then find t [1... Q-1], because T [1... K] is t [1... The maximum true prefix of q-1], so t [1... The maximum true prefix of K] is t [1... Q-1] is the second largest real prefix, so at this time not equal is to evaluate t [1... K], that is, next [next [q-1] = next [k]; this is changed to k = next [K], compare T [next [k] + 1] and T [Q]. If not, repeat this step until next [k] = 0; the value of J is traced back to 0 and matched from the beginning.

The next array can be obtained through the above two steps. The code is implemented as follows:

void GetNext(const char* str,int* next)//abcac{next[0] = 0;int m = strlen(str);int k = -1;for ( int q=1 ; q<m ; q++ ){while( k>0 && str[k+1] != str[q] )k = next[k];if( str[k+1] == str[q] )next[q] = ++k;elsenext[q] = 0;}}
Through the code above, we can find that you can get a shorter implementation by adjusting the initial value of K, as shown below:

void GetNext(const char* str,int* next){next[0] = 0;int m = strlen(str);int k = 0;for ( int q= 1; q<m ; q++ ){while(  k>0 && str[k] != str[q] )k = next[k];if ( str[k] == str[q] )k = k+1;next[q] = k;}}

3. KMP time complexity Calculation

To calculate the time complexity of kmp_matcher, we must first calculate the time complexity of getnext. The Code shows that the time complexity of the For Loop in getnext is m, while that of the while loop in ?? We can see that the while loop is limited by K> 0, and K ranges from greater than next [K]. That is to say, the operation in the while loop is reduced by K at a rate of at least 1, the value of K is restricted by K = k + 1 in for. The value of K is zero. While loop does not perform any operation. Therefore, the while loop is constrained by the for loop. After the value of K is reduced in the while loop, if the K value does not increase, the while loop will not perform any operation. Therefore, the time complexity of getnext is O (M), and the time complexity of kmp_matcher can be introduced as O (m + n ).

The complete code is as follows:

#include <stdio.h>#include <string.h>#define MAX_STRING_LEN 255void GetNext(const char* str,int* next){next[0] = 0;int m = strlen(str);int k = 0;for ( int q= 1; q<m ; q++ ){while(  k>0 && str[k] != str[q] )k = next[k];if ( str[k] == str[q] )k = k+1;next[q] = k;}}int KMP_Matcher(const char* strMain,const char* strSub){if ( NULL == strMain || NULL == strSub )return -1;int n = strlen(strMain);int m = strlen(strSub);int next[MAX_STRING_LEN] = {0};GetNext(strSub,next);int q = 0;for ( int i=0 ; i<n ; i++ ){while ( q>0 && strSub[q]!=strMain[i] )q = next[q];if ( strSub[q] == strMain[i] )q = q+1;if ( q==m-1 )return i-q+1;}return -1;}int main(int argc, char* argv[]){int nIndex = KMP_Matcher("aaababcacabcac","abcacab");printf("nIndex=%d",nIndex);getchar();return 0;}

Reference: algorithms and data structures Fu qingxiang and Wang Xiaodong


KMP mode matching

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.