KMP算法简介(next数组的计算方法)

网上不少KMP算法的实例和讲解,很多大神也对此进行了详细的讲解,作为一名大一的新接触算法的人而言,我对此感觉很高深,而且有些不耐烦看长篇大论的文章。
下面附上一个next计算的算法不错的博客,我就是从这里面学到的next算法
http://www.cnblogs.com/yjiyjige/p/3263858.html
这篇博客使用java编写的KMP算法,我使用的是C语言,对于初学者应该比较好懂

我先把自己的KMP算法打到这里,然后再慢慢分析

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

#define MAXSIZE 100
#define MINSIZE 30

void getNext(char sonString[MINSIZE], int next[MINSIZE]);
void KMP(char parentString[MAXSIZE], char sonString[MINSIZE], int next[MINSIZE]);

int main()
{
    char parentString[MAXSIZE];  //主串
    char sonString[MINSIZE];   //子串
    printf("please input parent string:\n");
    scanf("%s", parentString);
    fflush(stdin);  //清空缓冲区
    printf("please input son string:\n");
    scanf("%s", sonString);
    fflush(stdin);
    int *next = (int *) malloc(sizeof(int) * strlen(sonString));  //申请动态内存用于储存next
    getNext(sonString, next);  //获取next数据的函数
    KMP(parentString, sonString, next);  //执行KMP的算法
    return 0;
}

void  getNext(char sonString[MINSIZE], int next[MINSIZE])
{
    char sonStringTemp[MINSIZE];
    strcpy(sonStringTemp, sonString);   //使用一个临时数组来复制子串的值,主要是防止操作的过程中对原来的数组产生影响
    int i, j;
    j = 0;
    i = -1;
    next[0] = -1; //这里是先将第一个元素设置为一个-1,可以理解成一个标志性的变量
    //while循环里的代码建议多采用debug几次,慢慢就会明白代码的意思了,不得不承认这是一个很漂亮的算法
    while(j < strlen(sonStringTemp) - 1)
    {
        if(i == -1 || sonStringTemp[j] == sonStringTemp[i])
            next[++j] = ++i;
        else
            i = next[i];
    }
}

void KMP(char parentString[MAXSIZE], char sonString[MINSIZE], int next[MINSIZE])
{
    int i, j;
    i = 0;
    j = 0;
    while(j<(int)strlen(sonString) && i<(int)strlen(parentString))
    {
        if(j == -1 || sonString[j] == parentString[i])
        {
            i++;
            j++;
        }
        else
        {
            j = next[j];
        }
    }
    if(i>=strlen(sonString))
        printf("success %d\n", i-j+1);
    else
        printf("no this data\n");
}

我么先来看看next里的数据是怎么得到的

void  getNext(char sonString[MINSIZE], int next[MINSIZE])
{
    char sonStringTemp[MINSIZE];
    strcpy(sonStringTemp, sonString);   //使用一个临时数组来复制子串的值,主要是防止操作的过程中对原来的数组产生影响
    int i, j;
    j = 0;
    i = -1;
    next[0] = -1; //这里是先将第一个元素设置为一个-1,可以理解成一个标志性的变量
    //while循环里的代码建议多采用debug几次,慢慢就会明白代码的意思了,不得不承认这是一个很漂亮的算法
    while(j < strlen(sonStringTemp) - 1)
    {
        if(i == -1 || sonStringTemp[j] == sonStringTemp[i])
            next[++j] = ++i;
        else
            i = next[i];
    }
}

很有意思的是KMP算法里是防止回溯所带来的时间开销,而在求next的时候却在使用回溯来实现对next进行赋值,一般在一个KMP算法中会对next进行事先的约定,一般而言,是不使用数组的0号位置来存储数据的,但是这里为了减少对字符串的操作(个人认为C语言的字符串的操作太不方便),我们使用0号位置开始存储数据。
对next我们约定如下
《KMP算法简介(next数组的计算方法)》

对于while循环里的代码实际上就是一个“回溯的算法”,对于每次if语句里的判断不对的时候,i就会通过next数组向前回溯,然后直到找到和if语句里相匹配的位置。这里建议使用debug多进行几次就可以看出来了,推荐的使用的判断字符串
aabcaaabcad可以很好的测试next。

你可以先看next怎么用的,然后输出next里的数据,可以先不查找,先把next弄懂再进行下面的查找操作。

我们再来看一下KMP算法的查找部分

void KMP(char parentString[MAXSIZE], char sonString[MINSIZE], int next[MINSIZE])
{
    int i, j;
    i = 0;
    j = 0;
    while(j<(int)strlen(sonString) && i<(int)strlen(parentString))
    {
        if(j == -1 || sonString[j] == parentString[i])
        {
            i++;
            j++;
        }
        else
        {
            j = next[j];
        }
    }
    if(i>=strlen(sonString))
        printf("success %d\n", i-j+1);
    else
        printf("no this data\n");
}

如果明白KMP算法的原理,看这段代码应该很简单,需要注意的是strlen返回的是一个无符号整形,这里要使用强制类型转换。

本人也是刚刚学习的KMP算法,如有疏漏敬请指出。

    原文作者:KMP算法
    原文地址: https://blog.csdn.net/kejizuiqianfang/article/details/68958178
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞