一图胜千言
代码:
int KMPGetNext(const char* pc_str, int n)
{
const int STR_LEN = (NULL == pc_str) ? /
-1 : (int)strlen(pc_str);
const int END = n - 1;
int ret = 0;
int max_len = 0;
if ((NULL == pc_str) || (n < 1)) {
ret = -1;
goto END;
}
if (END >STR_LEN) {
ret = -1;
goto END;
}
for (max_len = END - 1; max_len >= 0; --max_len) {
int i = max_len, j = END;
while ((i >= 0) && (pc_str[i--] == pc_str[j--])) {
}
if (i < 0) {
ret = max_len;
goto END;
}
}
END:
return ret;
}
int KMP(const char* pc_str, const char* pc_sub)
{
const int STR_LEN = (NULL == pc_str) ? /
-1 : (int)strlen(pc_str);
const int SUB_LEN = (NULL == pc_sub) ? /
-1 : (int)strlen(pc_sub);
int ret = 0;
int i = 0, j = 0;
if ((NULL == pc_str) || (NULL == pc_sub)) {
ret = -1;
goto END;
}
if (STR_LEN < SUB_LEN) {
ret = -1;
goto END;
}
for (i = 0, j = 0; /
(i < STR_LEN) && (j < SUB_LEN); /
++i, ++j) {
if ((STR_LEN - i) < (SUB_LEN - j)) {
ret = -1;
break;
}
if (pc_str[ i ] != pc_sub[j]) {
j = KMPGetNext(pc_sub, j);
if (j > 0) {
--i;
}
}
}
if (SUB_LEN == j) {
ret = i - SUB_LEN;
}
END:
return ret;
}
上面的实现是错误的,现追加
static
void __gen_next__(char const *str,
intptr_t n,
intptr_t *next,
intptr_t m)
{
intptr_t i = 0;
intptr_t j = 1;
assert(m >= n);
next[i] = -1;
next[j] = 0;
while (j < n - 1) {
if ((str[i] == str[j])) {
next[j + 1] = i + 1;
++i;
++j;
} else {
i = next[i];
if (-1 == i) {
i = 0;
next[++j] = 0;
}
}
}
}
intptr_t kmp(const char* text, const char* pattern)
{
intptr_t rslt;
intptr_t text_len = strlen(text);
intptr_t pattern_len = strlen(pattern);
intptr_t *next = (intptr_t *)calloc(pattern_len, sizeof(intptr_t));
memset(next, 0, pattern_len);
__gen_next__(pattern, pattern_len, next, pattern_len);
#if 0
for (intptr_t i = 0; i < pattern_len; ++i) {
fprintf(stderr, "%ld: %ld\n", i, next[i]);
}
#endif
// do kmp
do {
intptr_t i = 0;
intptr_t j = 0;
while ((i < text_len) && (j < pattern_len)) {
if ((-1 == j) || (text[i] == pattern[j])) {
++i;
++j;
} else {
j = next[j];
}
}
if (j >= pattern_len) {
rslt = i - pattern_len;
} else {
rslt = -1;
}
} while (0);
free(next);
return rslt;
}