标签:
字串的定位操作通常称作模式匹配(其中子串成为模式串),是各种串处理系统中的重要操作之一.
在博文c语言实现字符串中给出了定位函数int string_index(h_string S, h_string T, int pos)的一种算法.该算法的基本思路:
从主串S的第pos个字符起和模式串T的第一个字符比较,若相等,则继续逐个比较后续字符;否则从主串S的下一个字符起再重新和模式串T的字符比较.依次类推,直至模式T中的每一个字符依次和主串S中的一个连续字符序列相等,则称匹配成功,函数返回值为和模式T中第一个相等的字符在主串S中的序号,否则称匹配不成功,函数返回值为-1
例如,设 S 为目标串, T 为模式串,且不妨设:
S=“
◆ 若 s[i…i+m-1]=t[0…m-1] :则称从位置 i = pos - 1开始的匹配成功,亦称模式 t 在目标 s 中出现;
◆否则匹配失败i=i+1,继续比较,直至i>n-m
在某些情况下,此算法的效率为O(n+m),其中n为主串S的长度,m为模式串T的长度.
例如,检查串”China”是否存在于下列主串时:
“More thoughts from users on the ground in China about ExpressVPN as seen on Twitter and Facebook! “
但是在某些情况下,此算法的效率为O(n*m).
例如,检查”00000001”是否存在于下列字串时:
“00000000000000000000000000000000000000000000000000000000000000001”
int string_index(h_string S, h_string T, int pos)
{
/* 若T为空串 */
if(!(T.length))
return -1;
/* 比较 */
/* 串S的起始位置 */
int i = pos -1;
/* 串T的起始位置 */
int j = 0;
while(i < S.length && j < T.length)
{
if(S.str[i] == T.str[j])
{
i += 1;
j += 1;
}
else
{
i = i -j + 1;
j = 0;
}
}
if (j >= T.length)
return (i - T.length);
return -1;
}
此算法可以在O(n+m)的时间复杂度下完成串的模式匹配操作.相比于前面的算法,其改进在于:
每当匹配过程中出现字符比较不相等时,不需要回溯i指针,而是利用已经得到的”部分匹配”的结果将模式串向右”滑动”尽可能远的一段距离之后,继续进行比较.
实现KMP算法的难点在于:当匹配过程中产生”失配”(即
设S为目标串,T为模式串,且不妨设:S=“
假设此时应与模式中第k(k
由前面得到的”部分匹配”,有下面等式:
根据上述的两个等式的左边相等可得:
由上式可知,当模式串满足式(3)的两个子串时,在匹配过程中,主串中第i个字符与模式串中第j个字符不相等时,仅将模式串向右滑动至模式串中第k个字符和主串第i个字符对齐继续比较即可
若令next[j]=k,则next[j]表明当前模式中第j个字符与主串相应字符失配时在模式串中需要重新和主串中该字符进行比较的字符的位置next函数的定义如下:
上述的讲述难以理解,配图说明
假设在我们的匹配过程中出现了这一种情况:
根据 KMP 算法,在该失配位会调用该位的 next 数组的值!在这里有必要来说一下 next 数组的作用!
首先,我们取之前已经匹配的部分(即蓝色的那部分!)
前面的next函数,体现到图中就是这个样子!
next 数组的作用如下图所示:
下一次匹配:
求模式串abaabcac的next函数值
此时主串i+1;next[0]=-1
此时,next[1]=0,即返回第一个字符
此时,next[2]=0,即返回第一个字符
当模式串第四个字符没有匹配
此时,next[3]=1,即返回第二个字符
当模式串第五个字符没有匹配
此时,next[4]=1,即返回第二个字符
当模式串第六个字符没有匹配
此时,next[5]=2,即返回第三个字符
当模式串第七个字符没有匹配
此时,next[6]=0,即返回第一个字符
当模式串第八个字符没有匹配
此时,next[7]=1,即返回第二个字符
可以把next函数求值问题看成模式匹配问题,整个模式串既是主串又是模式串。而在当前的匹配过程中,已有
这就是说,
同理,若
则有:
求模式串abaabcac的next函数值
1.根据定义可以知道
2.求
3.求
4.求
5.求
6.求
7.求
8.综上,next函数值如下:
int get_next(h_string S, int next[])
{
/* 根据next函数的定义 */
next[0] = -1;
next[1] = 0;
int i = 2;
int j = 0;
while(i < S.length)
{
if(j == -1 || S.str[i-1] == S.str[j])
{
next[i] = j + 1;
j = next[i];
i += 1;
}
else
j = next[j];
}
}
int main()
{
char *ch = "abaabcac";
int next[8];
get_next(ch, next);
int i = 0;
for(i = 0; i < 8;i++)
printf("%d ", next[i]);
printf("\n");
return 0;
}
运行结果
int string_index(h_string S, h_string T, int pos)
{
/* 如果模式串为空 */
if(!T.length)
return -1;
/* 主串的下标 */
int i = pos -1;
/* 模式串的下标 */
int j = 0;
while(i < S.length && j < T.length)
{
if(S.str[i] == T.str[j])
{
i++;
j++
}
else
{
j = next[j];
. }
}
if(j >= T.length)
return (i - T.length);
return -1;
}
标签:
原文地址:http://blog.csdn.net/lym152898/article/details/52276006