網上不少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算法,如有疏漏敬請指出。