kmp匹配演算法介紹及實現
阿新 • • 發佈:2018-12-20
KMP匹配演算法
最近在看程傑的《大話資料結構》一書,看到了第五章,這一章介紹了對串進行匹配的演算法,包括樸素模式匹配演算法和KMP模式匹配演算法。對於KMP演算法自己也是搞得有點暈乎了,在這裡記錄下,以後說不定徹底弄懂了就回來補上。
-
KMP演算法是由D.E.Knuth、J.H.Morris和V.R.Pratt三位前輩共同發表的一個模式匹配演算法,該演算法可以大大避免重複遍歷的情況。
-
我們把要查詢的字串稱為模式串pattern,相應的在某個字串中進行查詢是否包含模式串的稱為文字串text,也稱為主串。
-
KMP演算法的核心是字首表,也稱為next陣列的計算,next數組裡面存放的是模式串的最長前後綴的相似度。所謂前後綴是指模式串中的某個子串,而最長字首是指:該子串第一個字元開始,不包含最後一個字元的串,而最長字尾是指:該子串不包含第一個字元的串。
例子
比如模式串為abcabcd,其字首分別是: a ab abc abca abcab abcabc abcabcd 這些前後綴的相同的最長前後綴分別是: 0 0 0 1---->a 2---->ab 3---->abc 0 所以next陣列的值是{0, 0, 0, 1, 2, 3, 0} 。
程式碼實現
-
以上便是自己理解的部分,下面是實現程式碼:
獲取字首表: void get_prefix_table(const char *pPatternStr, int *next) { if(NULL == pPatternStr) return; int i = 1; int j = 0; int len = strlen(pPatternStr); if(len == 0) return; next[0] = 0; //規定是0 while(i < len) { if(pPatternStr[j] == pPatternStr[i]) { j++; next[i] = j; i++; } else { if(j > 0)//防止陣列越界 { j = next[j-1]; //回溯 } else { next[i] = 0; i++; //移動到下一位繼續 } } } for(i=len-1; i>0; i--)//next陣列往後移動一位,便於KMP演算法匹配實現 { next[i] = next[i-1]; } next[0] = -1; } /* KMP演算法實現 字串匹配 main_str: 主串 sub_str: 子串 pos: 從主串main_str的第pos位開始往後查詢與子串sub_str相匹配的串 return: 返回子串sub_str相匹配的第一個串的起始位置, 沒有匹配則返回-1 */ int kmp_search(const char *main_str, const char *sub_str, int pos) { if(pos<0 || !main_str || !sub_str) return -1; int i = pos; int j = 0; int main_len = strlen(main_str); int sub_len = strlen(sub_str); if(pos>main_len || !sub_len || !main_len) return -1;//越界或者空字串 int *next = (int *)malloc(sizeof(int) * sub_len); get_prefix_table(sub_str, next); while(i<main_len && j<sub_len) { if(j == sub_len-1 && main_str[i] == sub_str[j]) { free(next); return i-j; } if(main_str[i] == sub_str[j]) { i++; j++; } else { j = next[j]; if(-1 == j) { i++; j++; } } } free(next); return -1; }