星期四, 十月 12, 2006

基本算法连载(9)-模式匹配之KMP(Knuth-Pratt-Morris)

KMP算法,在《数据结构》课上听过,似是非懂,读完大学后全忘光了。Brute-Force算法,简单,谁都知道。从主串S的第pos个字符起与模式串进行比较,匹配不成功时,从主串S的第pos+1个字符重新与模式串进行比较。如果主串S的长度是n,模式串长度是m,那么Brute-Force的时间复杂度是o(m*n)。最坏情况出现在模式串的子串频繁出现在主串S中。虽然它的时间复杂度为o(m*n),但在一般情况下匹配时间为o(m+n),因此在实际中它被大量使用。
前几日,重新拾起了KMP算法,然后向MM讲解之。KMP的主要思想是:每当一趟匹配过程中出现字符比较不等时,不需回溯主串S的指针,而是利用已经得到的“部分匹配”结果将模式串向右“滑动”尽可能远的一段距离后,继续进行比较。
模式串到底向右滑动多少,在KMP算法中是用一个数组来存储的。针对模式串中的每个索引j,都将有一个对应的值。此值的含义为模式串中位置从0到j-1构成的串中所出现的首尾相同的子串的最大长度加1。
下面给出具体实现:
/*
* n is the length of text,while m is the length of pattern.
* And pos which is zero-indexed is the start point of search.
*/
int kmp(char* text,int n,char *pattern,int m,int pos){
int i,j;
//Generate the array of next
int* next = (int*)malloc(m*sizeof(int));
i = 0;
j = -1;
next[i] = j;
while(i<m){
if((j==-1) || (pattern[i]==pattern[j])){
i++;
j++;
if(pattern[i]!=pattern[j])
next[i] = j;
else
next[i] = next[j];
}else{
j = next[j];
}
}

int k = 0;
for(k=0;k<m;k++)
printf("next:%d\n",next[k]);

//Search
i = pos;
j = 0;
while(i<n&&j<m){
if((j==-1) || (text[i]==pattern[j])){
i++;
j++;
}else{
j = next[j];
}
}
if(j==m)
return i-m;
else
return 0;
}
KMP算法的时间开销包括两部分,一个是求next数组元素的值,此时的时间开销是o(m);一个是搜索,此时的时间开销是o(n)。因此,它的时间复杂度是o(m+n)

没有评论: