KMP演算法程式碼註釋
阿新 • • 發佈:2019-01-08
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void printNext(int next[], int size) {
for(int i = 0; i < size;++i)
printf("%d ", next[i]);
printf("\n\n");
}
// next[i]表示[0,...,i-1]的子串的最長公共前後綴長度
void getNext(char *p, int next[]) {
int len = strlen(p);
next [0] = -1; //初值為-1
int k = -1; // 表示[0,...,j]的next值
int j = 0;
while(j < len - 1) {
if(k == -1 || p[j] == p[k]) { // 匹配或者是沒有公共前後綴
++j;
++k;
next[j] = k;
}
else
k = next[k]; //由於出現不匹配現象,需要找更短的字首
}
}
int kmp(char *s, char *p ) {
int pLen = strlen(p), sLen = strlen(s);
int *next = malloc(sizeof(int) * pLen);
getNext(p, next);
printNext(next, pLen);
int i = 0, j = 0;
while(i < sLen && j < pLen) {
if(j == -1 || s[i] == p[j]) {
++i;
++j;
}
else // 當出現不匹配時,只需要將模式串向後移動[匹配長度 - next[j]]
j = next[j];
}
free(next);
if(j == pLen)
return i - j;
return -1;
}
int main()
{
char *s = "BBC ABCDAB ABCDABCDABDE", *p = "ABCDABD";
int pos = kmp(s, p);
printf("%d\n", pos);
if(pos != -1) {
printf("%s\n", s);
printf("%*s\n", pos + strlen(p), p);
}
return 0;
}
總結
1. next陣列是其前面的子串的最長公共前後綴長度
2. 在求next陣列的時候,要利用前面匹配的資訊。如果p[j] == p[k],
那麼next[j] = k + 1;反之,需要在其字首中找到一個字母等於p[j],
如果沒有的話,那麼next[j] = 0,有的話,next[j]=k+1,這裡的k不再是
next[j-1]。