KMP算法代码注释

#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]的nextint 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]。

猜你喜欢

转载自blog.csdn.net/w1157984197/article/details/81166025