数据结构 朴素算法与kmp算法
朴素算法
算法描述
对主串的每一个字符作为子串的开头,与要匹配的字符串进行匹配。对主串做大循环,每个字符开头做T的长度的小循环,知道匹配成功,或者全部遍历完成为止。
实现代码
假设主串S与要匹配的子串T的长度存在S[0]与T[0]中。
实现代码如下 :
//朴素算法代码实现
//返回子串T在主串S中第pos个字符后的为止。若不存在,则函数返回值为0。
//T非空,1<=pos<=StrLength(S)
int index( String S, String T, int pos )
{
//i用于主串S中当前位置下标,若pos不为1,则从pos位置开始匹配
int i = pos;
//j用于子串T中当前位置下标值
int j = 1;
//若i小于S长度且j小于T长度时循环
while( i <= S[0] && j <= T[0] )
{
//两字母相等则继续
if( S[i] == T[j] )
{
++i;
++j;
}
else//若两字母不相等,则指针后退重新开始匹配
{
i = i-j+2; //i退回到上次匹配首位的下一位
j = 1; //j退回到子串的首位
}
}
if( j>T[0] )
return i-T[0];
else
return 0;
}
时间复杂度
n为主串的长度,m为子串的长度,则根据等概率原则,平均是(n+m)/2次查找,时间复杂度为O( n + m )。
KMP算法
KMP模式匹配算法实现
计算next数组
//kmp模式匹配算法
//计算next数组
//通过计算,返回子串T的next数组
void get_next( String T, int *next )
{
int i, j;
i = 1;
j = 0;
next[1] = 0;
//此处T[0]表示子串T的长度
while( i<T[0] )
{
if( j==0 || T[i]==T[j] ) //T[i]表示后缀的单个字符,T[j]表示前缀的单个字符
{
++i;
++j;
next[i] = j;
}
else
j = next[j]; //字符不相等,则j值回溯
}
}
kmp模式实际匹配返回下标算法实现
//kmp模式匹配算法
//返回下标
//返回子串T在主串S中第pos个字符后的位置。若不存在,则返回值为0。
int Index_KMP ( String S, String T, int pos )
{
//i用于主串S当前位置下标值,若pos不为1,则从pos位置开始匹配
int i = pos;
//j用于子串T中当前位置下标值
int j = 1;
//定义next数组
int next[255];
//得到next数组
get_next( T, next );
while( i<=S[0] && j<=T[0] )
{
if( j==0 || T[i]==T[j] )
{
++i;
++j;
}
else
j = next[j];
}
if( j>T[0] )
return i-T[0];
else
return 0;
}
KMP模式匹配算法改进
计算nextval数组
//kmp模式匹配算法改进
//计算nextval数组
void get_nextval( String T, int *nextval )
{
int i, j;
i = 0;
j = 1;
next[1] = 0;
while( i<T[0] )
{
if( j==0 || T[i]==T[j] )
{
++i;
++j;
if( T[i] != T[j] ) //在kmp模式算法计算next数组中,next[i]=j
nextval[i] = j; //如果当前字符与next[i]值所指字符不同,则nextval[i]=next[i],即将对应next值照抄
else
nextval[i] = nextval[j]; 如果当前字符与next[j]值所指字符相同,则nextval[i]=nextval[enxt[i]] = nextval[j]
}
else
{
j = next[j];
}
}
}
实际匹配算法实现
只需将“get_next(T,next)"改为”get_nextval(T,next)"即可。
KMP模式改进算法总结
在计算出next数组的同时,如果a位字符与它next值指向的b位字符相等,则该a位字符的nextval值就指向b位的nextval值。如果不等,则a位的nextval值指向自己a位的next值。