串的模式匹配(朴素算法和KMP算法以及KMP的改进算法)
在学习算法之前我们先认识一些术语
子串:串中任意个连续的字符组成的子序列.
主串:包含子串的串
模式串:在主串中要查找的子串
串的模式匹配一般有两种算法即朴素算法和KMP算法,下面我们来一一介绍
一、朴素算法(暴力算法)
算法思想
1. 将主串中所有长度为m的子串与模式串对比
2.主串长度n,模式串长度m
3.找到第一个与模式串匹配的子串,并返回子串起始位置
4.若所有子串都不匹配,则返回0
因为朴素算法通过一个一个比较来找到主串中包含的模式串,所以时间复杂度为O(nm)
代码实现:
#include <stdio.h>
#include<string.h>
int main()
{
char S[] = "aaaab";//主串
char Q[] = "aac";//模式串
int Slen = (int)strlen(S);
int Qlen = (int)strlen(Q);
int i, j;
i = j = 0;
while (i < Slen && j < Qlen)
{
if (S[i] != Q[j])
{
i = i - j + 1;
j = 0;
}
else
{
i++;
j++;
}
}
if (j == Qlen)
printf("找到了\n");
else
printf("没找到\n");
return 0;
}
二、KMP算法
算法思想
1.主串长度n,模式串长度m
2.利用两个指针i和j,i指向主串,j指向模式串
3.如果发现i不等于j的话,i不动,j指向next数组的下标
4.若所有子串都不匹配,则返回0
求next数组的方法
1.Next[1]可以直接写0
2.Next[2]可以直接写1
3.其他的next在不匹配的位置前,划一条分界线,模式串一步一步往后退,知道分界线之 前 “能对上”,或模式串完全跨过分界线为止。
此时j指向哪里,next数值就是多少
代码实现:
#include<stdio.h>
#include<string.h>
#define MainLen 7
#define ModelLen 4
int main()
{
char arr[] = "abaabab";//定义主串
char S[] = "aaba";//模式串
int next[ModelLen] = {-1,0,1,0};//next数组,根据上面的方法手动模拟
int i = 0;
int j = 0;
while (i < MainLen && j < ModelLen)
{
if (j == -1 || arr[i] == S[j])
{
i++;
j++;
}
else
{
j = next[j];
}
}
if (j == ModelLen)
printf("找到了\n");
else
printf("没找到\n");
return 0;
}
KMP算法的时间复杂度为O(n+m)相比于朴素算法提高了很多
三、KMP算法的优化
KMP的优化算法主要是优化了next数组的逻辑
如果当前匹配失败的这个元素,与next[j]指向的下一个元素一样的话
那么下一个数也一定会失败,所以我们可以减少不必要的比较
如果当前失败的元素与下一个要比较的元素的一样的话,我们可以直接令当前失败的元素直接指向下一次要比较的元素下标
#include<stdio.h>
#include<string.h>
#define MainLen 7
#define ModelLen 4
int main()
{
char arr[] = "abaabab";//定义主串
char S[] = "aaba";//模式串
int next[ModelLen] = { -1,0,1,0 };//next数组,根据上面的方法手动模拟
//注:408考试中只要求会手写 我把手写和代码都写出来可供参考
//int nextval[ModelLen] = {-1,-1,1,-1}; //优化数组
int nextval[ModelLen] = {0};
//下面是代码的实现(408不要求)
nextval[0] = -1;//第一个数固定为-1
int x = 1;
for (x; x < ModelLen; x++)
{
if (S[x] == S[next[x]])//如果当前的数与下一个数相等的话
nextval[x] = nextval[next[x]];//直接令当前的元素下标等于下一个元素指向的下标
else
nextval[x] = next[x];//如果不相等直接赋值
}
int i = 0;
int j = 0;
while (i < MainLen && j < ModelLen)
{
if (j == -1 || arr[i] == S[j])
{
i++;
j++;
}
else
{
j = nextval[j];
}
}
if (j == ModelLen)
printf("找到了\n");
else
printf("没找到\n");
return 0;
}