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我們約定如下
這裏寫圖片描述

對於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算法,如有疏漏敬請指出。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章