算法简述:
KMP算法是将字符串匹配过程中的信息运用起来实现每一次匹配过程主数据不回退例如:
主数据:A : abccdbbdhjbabcabcdga
匹配字符串: B:abcabcd
以第一次匹配为例:当主数据匹配到’c‘时不再适配此时匹配字符串中已经匹配的字符为“abca”此时可以得到主数据中第一次匹配字符后二个字符为’b‘和’c‘所以我们可以运用这一信息从而避免在失配后主数据退回’b'重新比较,以此达到降低时间复杂度的目的。
信息运用:
观察数据“abca”可以发现真正有用的信息是“bc”即匹配字符失配位置以前除去第一个字符为有效字符(也就是主数据中需要重新比较的字符)所以我们可以以匹配字符串的回退代替主数据回退。为达到这一目的我们引入了next数组以记录匹配字符串每个位置失配后匹配位置需要回退的位置以代替主数据回退。
next数组求法
next数组第一个数字为-1(触底标志)第二个为0。求第n个位置next数组值则比较匹配字符串第n-1个位置B[n-2]与第n-1个位置对应的next[n-2]所对应位置的匹配字符串字符B[next[n-2]]是否相等若相等next[n-1]=next[n-2]+1否则就继续和B[next[next[n-2]]]比较若触底则next[n-1]=0
注:next数组写法形式有多种、
代码实现:
int* Get_Next(char* arr, char* brr)//arr为主数据,brr为匹配字符串
{
int len = strlen(brr);//next数组长度
int* next = (int*)malloc(len * sizeof(int));
next[0] = -1;//设置触底标志
if (len > 1)//防止brr数组只有一个值
next[1] = 0;
int i = 1;//代表brr位置
int j = 0;//要比较的next数组位置
while (i < len - 1)//求next数组
{
if (j==-1||brr[i] == brr[j])
{
i++;
j++;
next[i] = j;
}
else
{
j = next[j];//匹配字符串回退
}
}
return next;
}
bool KMP(char* arr, char* brr)//arr为主数据,brr为匹配字符串
{
int* next = Get_Next(arr, brr);
int i = 0;
int j = 0;
int len1 = strlen(arr);
int len2 = strlen(brr);
while (i < len1 && j < len2)//进行匹配
{
if (arr[i] == brr[j]||j==-1)
{
i++;
j++;
}
else
{
j = next[j];//匹配字符串回退
}
}
if (j == len2)//如果完全匹配
return true;
else
return false;
}
next数组优化nextval数组:
在next数组中若出现B为“aaaabb”这类情况其next数组值为“-1,0,1,2,3,0”当其在第五个位置发生失配时此时主数据还要和B[3],B[2],B[1]比较但是这些位置的值相同是比较结果也一样是完全可以省略的。
代码实现:
int* Get_Next(char* arr, char* brr)//arr为主数据,brr为匹配字符串
{
int len = strlen(brr);//next数组长度
int* nextval = (int*)malloc(len * sizeof(int));
nextval[0] = -1;//设置触底标志
if (len > 1)//防止brr数组只有一个值
nextval[1] = 0;
int i = 1;//代表brr位置
int j = 0;//要比较的next数组位置
while (i < len - 1)
{
if (j==-1||brr[i] == brr[j])
{
i++;
j++;
nextval[i] = j;
}
else
{
j = nextval[j];//匹配字符串回退
}
}
for (int i = 1; i < len; i++)//nextval优化
{
if (brr[i] == brr[nextval[i]])
nextval[i] = nextval[nextval[i]];
}
return nextval;
}