http://www.inf.fh-flensburg.de/lang/algorithmen/pattern/kmpen.htm
http://www.ics.uci.edu/~eppstein/161/960227.html
T爲主串ababaaababaaababaa,大小爲18;p爲模式串ababaa,大小爲6;
不免俗的我們先看下,普通的字符串匹配算法核心代碼:
for (i=0; T[i] != '\0'; i++)
{
for (j=0; T[i+j] != '\0' && P[j] != '\0' && T[i+j]==P[j]; j++)
; //這有個分號喲。
if (P[j] == '\0')
{
report(i);//找到了一個匹配的
}
}
外循環主串索引i每次++,共18次,一路加到底。每次內循環模式串的索引j 變化範圍不定。最壞爲6次++運算。 算法的最壞情況18*6
KMP算法:
先看幾個概念:
前綴串:
A prefix of x is a substring u with u = x0 ... xb-1 where b {0, ..., k} i.e. x starts with u.
後綴串:
A suffix of x is a substring u with u = xk-b ... xk-1 where b {0, ..., k} i.e. x ends with u.
真前綴串和真後綴串:
A prefix u of x or a suffix u of x is called a proper prefix or suffix, respectively, if ux, i.e. if its length b is less than k.
邊界串:
A border of x is a substring r with r = x0 ... xb-1 and r = xk-b ... xk-1 where b {0, ..., k-1}
注意,邊界串的定義是必須同時滿足 真前綴串和真後綴串 的字符串才能被稱作 邊界串!!通俗點,邊界串就是兩頭相等的前後綴串的合體。
r 和 s 都是邊界串!
邊界串擴展:
Let x be a string and a A a symbol. A border r of x can be extended by a, if ra is a border of xa.
下圖中r邊界串被擴展成ra邊界串了。
下面的代碼中:
數組b[]就是我們求出的模式串中每個元素的border值——就是邊界串的長度。
好吧,讓我們從頭說起,話說不知那一天高德納老爺爺,抱怨 普通字符串匹配算法效率太差了,就想改進他,怎麼改進他呢?
本質上就是減少普通字符串匹配算法中內外曾循環的次數,這就用到了邊界串了!
在下面的代碼中,我們看到外層循環索引還是++ 了18次。
改變的是內層的循環次數,至於怎麼減少的自己理解去吧!還用說就是用着個border值唄!border值就是網上的next值是也!
那,這個border值怎麼求的?請跳到下一段。
void kmpSearch()
{
int i=0, j=0;//i爲主串索引,j爲模式串索引
for ( ;i < 18; )//你瞧,和普通的字符串匹配算法多像呀:-)
{
for ( ; j>=0 && T[i]!=p[j]; )
j=b[j]; //就是這裏了提高了效率
i++; j++;
if (j==m)
{
report(i-j);// 找到了,i-j 爲模式串在主串最初出現的位置。
j=b[j];
}
}
}
KMP算的核心組件:預處理 算法
把下面這句看懂了,border 你就懂了。
The preprocessing algorithm comprises a loop with a variable j assuming these values. A border of width j can be extended by pi, ifpj = pi. If not, the next-widest border is examined by setting j = b[j]. The loop terminates at the latest if no border can be extended (j = -1).
void kmpPreprocess() //求模式串中每個元素的border值。
{
int i=0, j=-1;//i爲模式串的索引,j爲當前處理到第i個模式串中的元素的border值。
b[i]=j; //b[] 是全局數組
while (i<m)
{
while (j>=0 && p[i]!=p[j]) j=b[j]; //這句是核心請舉例畫圖,就可以明白配合上面的英文解釋。
i++; j++;
b[i]=j;
}
}