一直以來,對算法都是理論大於實際,甚至沒有實際.
最近由於項目需要.從新瞭解了一下KMP算法.唉,討厭這種被動的學習過程.
不過KMP算法還是很有意思的,用了兩天的時間才總算是弄懂了.期間參考了網上的博文和數據結構.下面分享一下KMP算法的心得.
KMP的總體思想是利用模式串本身的特性來優化匹配的步驟.如何利用自身的特性呢,KMP藉助一個數組來實現,也就是大多數教程中提到的next數組.後面我會介紹next數組是如何構建和使用的.
前面提到KMP算法需要模式串滿足一定的條件,那麼這個條件是什麼呢.這裏直接引用數據結構書中的等式:
當k < j 時, t1t2…tk-1tk = tj-(k-1)tj-k… tj-1 tj.
如果沒有這個等式,那麼KMP算法無異於浪費了next大小的空間的最普通的字符串匹配算法.
下面用一張圖來描述一下這個等式在匹配子串的時候起到的作用:
(本圖片假定數組下標從1開始)首先我們找到等式: t1t2 = t6t7.所以當t8不匹配的時候,KMP算法會自動對齊t1 t2 然後用t3和母串進行匹配.
那麼根據以上的分析,我們可以得出以下的幾個結論(可能得出的有點倉促,同學們還是需要結合課本來進行理解)
1. next數組和模式串的下標是一一對應的.
2. 每個字符對應的next保存的是其前一個字符匹配的前綴的下標.從上面的圖中可以看到next[8]保存的是3.
3. 第一個字母沒有前綴,所以它的next保存的是一個無效的下標.在實際編程中,可以是-1
4. 如果一個字符的前面沒有滿足等式的子串,則其next保存的是模式串的首字母的下標.
根據我們的結論,下面給出KMP算法的實現:
void kmp_get_next(char *pattern, int next[])
{
int i = 0, j = 0;
next[i] = -1;
while (i < strlen(pattern) - 1)
{
if (j == i || pattern[i] == pattern[j])
{
if (j != i)
{
j++;
}
i++;
next[i] = j;
}
else if (j != 0)
{
j = next[j];
}
else
{
i++;
}
}
}
void kmp_print_next(char *pattern, int next[])
{
int i = 0;
if (NULL == pattern)
{
return;
}
printf("%s 's next array is : \n", pattern);
for (i = 0; i < strlen(pattern); i++)
{
printf("%d\t", next[i]);
}
}
int kmp_is_match(char *pattern, char *basestr, int next[])
{
int i = 0;
int j = 0;
while (i < strlen(basestr))
{
if (basestr[i] == basestr[j])
{
if (j == strlen(pattern))
{
return 0;
}
i++;
j++;
}
else
{
j = next[j];
if (j == -1)
{
i++;
}
}
}
return -1;
}
int kmp_get_match(char *pattern, char *basestr, int next[])
{
int i = 0;
int j = 0;
while (i < strlen(basestr))
{
if (basestr[i] == basestr[j])
{
if (j == strlen(pattern))
{
return i;
}
i++;
j++;
}
else
{
j = next[j];
if (j == -1)
{
i++;
}
}
}
return -1;
}
#include "kmp.h"
int main(int argc, char **argv)
{
int ret = 0;
int i = 0;
char *pattern = "abaabc";
int next[10] = {0};
char *basestr = "abcabcabcabccacabdabaabcabceadb";
kmp_get_next(pattern, next);
printf("%s matched\n", kmp_is_match(pattern, basestr, next) == 0 ? "is" : "not");
ret = kmp_get_match(pattern, basestr, next);
return 0;
}
KMP算法其實理解起來並不難,比較難的就是構造next數組.至少對我而言是這樣.一旦數組構造出來,那剩下的就都好辦了.
可能是我理解的還不夠深把,寫之前覺得有很多內容可以分享,但是開始寫以後發現不知道該寫什麼.希望能夠對同學們有所啓發.