定位字符串P在字符串S中的位置,可以称作
字符串的模式匹配
最简单最容易想到的匹配算法是 O(M*N)
//int search(char const*, int, char const*, int)
//查找出模式串patn在主串src中第一次出现的位置
//plen为模式串的长度
//返回patn在src中出现的位置,当src中并没有patn时,返回-1
int search(char const* src, int slen, char const* patn, int plen)
{
int i = 0, j = 0;
while( i < slen && j < plen )
{
if( src[i] == patn[j] ) //如果相同,则两者++,继续比较
{
++i;
++j;
}
else
{
//否则,指针回溯,重新开始匹配
i = i - (j - 1); //退回到最开始时比较的位置
j = 0;
}
}
if( j >= plen )
return i - plen; //如果字符串相同的长度大于模式串的长度,则匹配成功
else
return -1;
}
KMP算法不需要回溯主串,只考虑模式串,O(M+N)
//代码2-1
//int kmp_seach(char const*, int, char const*, int, int const*, int pos) KMP模式匹配函数
//输入:src, slen主串
//输入:patn, plen模式串
//输入:nextval KMP算法中的next函数值数组
int kmp_search(char const* src, int slen, char const* patn, int plen, int const* nextval, int pos)
{
int i = pos;
int j = 0;
while ( i < slen && j < plen )
{
if( j == -1 || src[i] == patn[j] )
{
++i;
++j; //匹配成功,就++,继续比较。
}
else
{
j = nextval[j];
//当在j处,P[j]与S[i]匹配失败的时候直接用patn[nextval[j]]继续与S[i]比较,
//所以,Kmp算法的关键之处就在于怎么求这个值拉,
//即匹配失效后下一次匹配的位置。下面,具体阐述。
}
}
if( j >= plen )
return i-plen;
else
return -1;
}
模式串的next[]数组计算方法:用KMP算法,模式串与自身作比较
void get_next(char const* ptrn, int plen, int* nextval)
{
int i = 0;
nextval[i] = -1;
int j = -1;
while( i < plen-1 )
{
if( j == -1 || ptrn[i] == ptrn[j] ) //循环的if部分
{
++i;
++j;
nextval[i] = j;
}
else //循环的else部分
j = nextval[j]; //递推
}
}
next[]数组的改进计算方法:
void get_nextval(char const* ptrn, int plen, int* nextval)
{
int i = 0;
nextval[i] = -1;
int j = -1;
while( i < plen-1 )
{
if( j == -1 || ptrn[i] == ptrn[j] ) //循环的if部分
{
++i;
++j;
//修正的地方就发生下面这4行
if( ptrn[i] != ptrn[j] ) //++i,++j之后,再次判断ptrn[i]与ptrn[j]的关系
nextval[i] = j; //之前的错误解法就在于整个判断只有这一句。
else
nextval[i] = nextval[j];
}
else //循环的else部分
j = nextval[j];
}
}