一.KMP算法
1.用途
KMP算法主要用于字符串的匹配问题。
例如:
-
第一种办法是暴力解法,依次遍历寻找,在文本串中找到第一次与模式串第一个字符相等的字符后,依次遍历如果文本串中出现与模式串不相等的字符,然后再从文本串的下一个字符再遍历出与模式串相等的字符,再遍历下面的是否与模式串相等,直到全部相等为止。这样看出是非常复杂而且时间复炸度是很高的。
-
第二种办法是KMP算法很好的解决了复杂度高的问题,先开始遍历文本串与模式串,当文本串中出现与模式串不相同的字符时,它会跳到模式串的第一个字符与文本串不相同的字符之间,再与该文本串的字符进行比较。
如上面的例子。文本串中的位置不变,只是模式串中的位置变了。
那怎样可以使模式串从f跳到b呢?这里需要建立一个next[]数组。
2.next数组建立
1.前缀表
- 前缀:包含首字母,不包含尾字母的所有字串。
- 后缀:包含尾字母,不包含首字母的所有字串。
前缀表求的使两字符串之间,前缀与后缀相等的最长字串的长度。next数组中保存的数据就是模式串中,从0号下标开始到最后一个下标的字符的最长字串的长度。
next数组中保存的就是前缀与后缀中最长子串的长度。如上面例子next[]={0,1,0,1,2,0};
那它是如何从模式串的f跳到b的呢?
已知next数组个数与模式串中的有效字符个数相等,当模式串中的字符f与文本串中的字符不相等时,它会将next[模式串中与文本串字符不相等的下标-1]的值
作为下标赋给模式串。这样就实现了模式串冲f跳到b。
比如上面例子中:模式串与文本串不相等字符f下标为5,然后next就会将next[5-1]=2作为下标赋给模式串,即 模式串[2]。再与文本串中的字符进行比较。
2.next数组用代码实现
因为next数组里放的模拟串前缀与后缀相等的最长字串的长度,所以讨论的时模拟串前缀和后缀。
- 思想:
首先要建立两个变量,i(后缀尾),j(前缀尾和前缀与后缀相等的最长字串的长度)注意j有两层含义。
然后进行初始化。
再讨论前缀尾与后缀尾不相等的情况。这个必须先考虑,因为当前缀与后缀相等时再来更新j。
最后讨论前缀尾与后缀尾相等的情况。
void Getnext(int *next, const char *p){
int j = 0;
next[0] = 0;//一开始初始化为0,因为一开始没有前缀和后缀。
for (unsigned int i = 1; i < strlen(p); i++){
while (p[i] != p[j] && j>0){//注意是循环,依次找前缀尾是否与后缀尾相等,直到相等或到了最开始的位置。
j = next[j - 1];//回退是回退到next[j-1]处
} //这个必须在相等上面,直到找到相等的才退出更新j。
if (p[i] == p[j]){
j++;
}
next[i] = j;
}
}
个人的理解为什么跳到上一个next数的位置,
理解next数组怎么来的,需手画一下,或者看链接。
或者看着链接:https://www.bilibili.com/video/BV1PD4y1o7nd
https://www.bilibili.com/video/BV1M5411j7Xx
3.用KMP算法实现strstr函数
#include<stdio.h>
void Getnext(int *next, const char *p){
int j = 0;
next[0] = 0;
for (unsigned int i = 1; i < strlen(p); i++){
while (p[i] != p[j] && j>0){
j = next[j - 1];//这个必须在相等上面,直到找到相等的才退出更新j。
}
if (p[i] == p[j]){
j++;
}
next[i] = j;
}
}
int Mystrstr(const char *arr, const char *p){
int *next = (int *)malloc(sizeof(int)*strlen(p));
Getnext(next, p);
int j = 0;
for (unsigned int i = 0; i<strlen(arr); i++){
while (arr[i] != p[j] && j>0){
j = next[j - 1];
}
if (arr[i] == p[j]){
j++;
}
if (j == strlen(p)){
return i - strlen(p) + 1;
}
}
return -1;
}
int main(){
char *arr = "hellow";
int n = Mystrstr(arr, "ll");
printf("%d\n", n);
return 0;
}
返回第一次出现字符串的下标。