最近工做稍閒,有空看了下算法導論字符串匹配部分,本身簡單概括總結下: 算法
介紹The Knuth-Morris-Pratt algorithm 算法前必需要介紹 模式字串前綴函數(Theprefix function for a pattern) 函數
首先假設 input text 爲待匹配的字符串,pattern 爲要匹配的字符子串; spa
一、The prefix function for a pattern:模式字串前綴函數π是 pattern 和本身的位移的匹配信息; code
假設當前匹配以下圖示(a): 字符串
咱們能夠經過前面已經匹配的部分字符串信息來計算下一個須要匹配的位置(避免掉無效的匹配); input
這時候能夠先計算pattern 和 已經匹配部分(對應前面pattern 本身的位移)的匹配信息,就是咱們下一個須要匹配的位置;通俗來說,就是求pattern 最長的前綴同時是已經匹配部分字串的後綴,這樣這部分就能夠跳過匹配了;計算以下圖示(c): string
能夠看出字串"aba" 便是部分匹配字串(「ababa」) 的後綴,同時是pattern("ababaca")的前綴,其長度爲3,便可以跳過pattern 前3位,直接用圖示(a)不匹配的 位‘a’ 和 pattern[3] 來匹配: it
二、下面咱們來看下前綴函數的code,以及完整KMP match algorithm: io
/* 這裏須要注意的是pi_array的下標是以1開始到pattern_len, 也能夠本身修改爲以0爲開始下標,須要對算法比較 理解才行~ */ int compute_prefix_function(char const* pattern_str, int pattern_len, int * pi_array) { if(NULL == pattern_str) { printf("pattern_str is null !\n"); return -1; } int k = 0; int q = 0; int m = pattern_len; pi_array[1] = 0; for(q = 2; q <= m; q++) { while((k>0)&&(pattern_str[k] != pattern_str[q-1])) { /* 取pattern[0~k-1]的最大前綴同時也是後綴 pattern[0~q-1]是已經匹配的 */ k = pi_array[k]; } if(pattern_str[k] == pattern_str[q-1]) { k++; } pi_array[q] = k; } return 0; } int kmp_string_match(char const* input_str, int input_len, char const* pattern_str, int pattern_len) { if(NULL == input_str || NULL == pattern_str) { printf("input_str or pattern_str is null !\n"); return -1; } int* pi_array = new int[pattern_len+1]; int n = input_len; int m = pattern_len; int i = 0, q = 0; compute_prefix_function(pattern_str, pattern_len, pi_array); //--test code for(i = 1; i< m+1; i++) printf("pi_array[%d] = [%d]\n", i, pi_array[i]); //--end of test code for(i = 0; i <n; i++) { while((q>0)&&(pattern_str[q] != input_str[i])) { /* 取pattern[0~q-1]的最大前綴同時也是後綴,由於 pattern[0~q-1]是已經匹配的,下面是整個匹配過程: abababacababaca ababaca ababaca ababaca */ q = pi_array[q]; } if(pattern_str[q] == input_str[i]) { q++; } if(q == m) { printf("Pattern string occurs with shifts %d\n", i-(q-1)); q = pi_array[q]; } } delete [] pi_array; return 0; } int main(void) { char input[] = "abababacababaca"; char pattern[] = "ababaca"; kmp_string_match(input, strlen(input), pattern, strlen(pattern)); return 0; }
能夠看出二者兩個匹配函數比較相似,由於一個是pattern 和本身的位移匹配,另外一個是input text 和pattern 的匹配;具體你們能夠去看下算法導論。 function
參考:
一、《Introduction to algorithms》