您的位置:首页 > 其它

KMP算法(未优化版本,算法导论原版)

2017-12-12 20:42 288 查看
kmp是经典的单模式串字符串匹配算法,对于一个字符串在长文本中的匹配很有效。
kmp算法包括两部分,对模式串的预处理和模式串匹配**


1、模式串预处理

这一部分关键在于next数组的构造,相当于对模式串进行kmp匹配。注意,字符串数组与next数组的首字符不存储信息。

next数组中储存当该字符的下一个不匹配时,下一步应当跳转到哪里,即,到此为止该字符串的最长公共前缀,后缀的长度。

详细见代码注释



void next(int *next, char *c)//字符串从c[1]开始赋值
{
//k为要比较的字符的前一个的下标,一开始比较c[1]c[2],所以k初始化为0
int k = 0;
//首字符的next值初始化为0,说明包①含这个字符的字符串前后缀长为0,②即要比较的字符c[1]的前一个
next[1] = 0;//注意next数组值的两层含义
//一开始比较c[1]c[2],i初始化为2,
for (int i = 2; i < strlen(c); i++)//next数组最后一个的值比strlen值小一,所以不要取等
{
//当k可以回溯且不匹配时,让k回溯
//k初始化为0,保证可回溯,即k>0
while (k > 0 && c[i] != c[k + 1])
{
k = next[k];//对前串来说a[k]是a1中前缀的最后一个字符所在位置
}
if (c[i] == c[k + 1])//若匹配则k+1,
k++;
next[i] = k;//包含i的字符串的前缀长=加过1的k。
}
}


2、kmp匹配部分

原理与模式串匹配相似,只不过是两个字符串的匹配

void kmp(char *t, char *p)//t为长串,p为短串
{
int *next;
next = (int *)malloc(sizeof(int)*(strlen(p)+1));
buildnext(next, p);
int k = 0;//k为要比较的字符的前一个的下标,一开始比较模式串中的c[1],k初始化为0
for (int i = 1; i < strlen(t); i++)//长串的最后一个字符的下标为长度-1
{
while (k>1 && p[k + 1] != t[i])
k = next[k];
if (p[k + 1] == t[i])
k++;
if (k == strlen(p)-1)
{
printf("开始下标为%d\n", i - strlen(p)+1+1);
k = next[k];//寻找下一个匹配串
}
}


这种原始的kmp算法有一个弊端,当字符串重复性很高时(例如ababababag),它的效率和朴素匹配没啥区别了。因为当重复性很高时,如果有一位失配,那么再向后移动仍然失配。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法导论 算法 kmp