KMP算法

Posted dengschoo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了KMP算法相关的知识,希望对你有一定的参考价值。

KMP算法学习

KMP中用到的函数详解

1. prefix_table()

void prefix_table(char pattern[], int prefix[], int n ) { //用于求取前缀表
    prefix[0]  = 0; //开始的第一个字符置为0 , 后续函数将数组整体后移
    int len    = 0;// len指能匹配到的前缀和 和 后缀和的长度
    int i = 1; // 从第二个字符开始 pattern的游标
    while (i < n) {
        if (pattern[i] == pattern[len]) { //如果发现相等
            len++; // 匹配长度++
            i++; //游标后移
            prefix[i] = len; // 第i个字符的前缀表中的值为 len
        }
        else { //不相等的情况
            if (len > 0) // 斜对齐(前缀表整体后移的情况 prefix[0] = -1)
                len = prefix[len - 1];
            else { // 防止进入死循环
                prefix[i] = len;
                i++;
            }
        }
    }
}

2. move_prefix_table()

void move_prefix_table (int prefix[], int n) { // 将整个后缀表后移
    for (int i = n - 1; i > 0; i++) {
        prefix[i] = prefix[i -1];
    }
    prefix[0] = -1;
}
void kmp_search(char text[], char pattern[]) {
    int n = strlen(pattern);
    int *prefix = (int *)malloc( sizeof(int) * n);
    prefix_table(pattern, prefix, n);
    move_prefix_table(prefix, n);

    // text[i]      len(text)    = m
    // pattern[j]   len(pattern) = n
    int i = 0, j = 0;
    int m = strlen(text);
    int n = strlen(pattern);

    while (i < m) {
        if ( j == n -1 && text[i] == pattern[j]) { // 匹配到的条件
            printf("Found patten at %d.
", i - j); // i - j是子串的起始位置
            j = prefix[j]; // 如果多次出现则继续寻找
        }
        if (text[i] == pattern[j]) { // 正常匹配到则游标右移
            i++;
            j++;
        }
        else { //不匹配的情况
            j = prefix[j];//将pattern的游标拉到prefix继续匹配
            if (j == -1) { // j == -1说明首次未能匹配 则重新开始匹配
                i++;
                j++;
            }
        }
    }
}

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void prefix_table(char pattern[], int prefix[], int n ) {
    prefix[0]  = 0;
    int len    = 0;
    int i = 1;
    while (i < n) {
        if (pattern[i] == pattern[len]) {
            len++;
            i++;
            prefix[i] = len;
        }
        else {
            if (len > 0)
                len = prefix[len - 1];
            else {
                prefix[i] = len;
                i++;
            }
        }
    }
}
void move_prefix_table (int prefix[], int n) {
    for (int i = n - 1; i > 0; i++) {
        prefix[i] = prefix[i -1];
    }
    prefix[0] = -1;
}
void kmp_search(char text[], char pattern[]) {
    int n = strlen(pattern);
    int *prefix = (int *)malloc( sizeof(int) * n);
    prefix_table(pattern, prefix, n);
    move_prefix_table(prefix, n);

    // text[i]      len(text)    = m
    // pattern[j]   len(pattern) = n
    int i = 0, j = 0;
    int m = strlen(text);
    int n = strlen(pattern);

    while (i < m) {
        if ( j == n -1 && text[i] == pattern[j]) {
            printf("Found patten at %d.
", i - j);
            j = prefix[j];
        }
        if (text[i] == pattern[j]) {
            i++;
            j++;

        }
        else {
            j = prefix[j];
            if (j == -1) {
                i++;
                j++;
            }
        }
    }
}

int main() {

    char pattern[] = "ABABCABABA";
    char text[]    = "ABABABCABAABABABAB";
    kmp_search(text, pattern);
    /*int prefix[9];
    int n = 9;
    prefix_table(pattern, prefix, n);
    move_prefix_table(prefix, n);
    for (int i = 0; i < n; i++) {
        printf("%d ", prefix[i]);
    }
    printf("
");*/
    return 0;
}

以上是关于KMP算法的主要内容,如果未能解决你的问题,请参考以下文章

数据结构—串KMP模式匹配算法

Python ---- KMP(博文推荐+代码)

KMP算法及Python代码

KMP算法及Python代码

图解KMP算法原理及其代码分析

Kmp算法Java代码实现