字符串
定义:串(String)是由零个或多个字符组成的有限序列,又名叫字符串。
- 一般记为 s= “a1a2a3…an”(n >= 0)
- 串可以是空串,即没有字符,直接由" "表示(注意里面没有空格)
- 子串和主串:例如over是lover的子串
字符串的比较
字符串比较大小跟传统的数字比较有点差别,字符串比的是每个字符的ASCII码大小
但直接比较大小没有意义,字符串的比较更重视是否相等
字符串的存储结构
- 字符串的存储结构与线性表相同,也分顺序存储结构和链式存储结构
- 字符串的顺序存储结构是用一组地址的连续存储单元来存储串中的字符序列的
- 按照预定义的大小,为每个定义的字符串变量分配一个固定长度的存储区,一般用定长数组来定义
- 与线性表相似,既然是固定长度的存储区,就存在一个空间分配不灵活的问题,就会考虑链式存储结构
- 不同的是字符串我们一般都是连在一起表述的,所以习惯上我们通常还是会直接定义一个足够长的存储区来存储
BF算法
BF算法属于朴素的模式匹配算法
每一次模式串都向下移动一个单位,直到字符串的末尾戒指,时间复杂度为字符串S与模式串T长度的乘积,即O(n*m)
KMP算法
前缀和后缀的概念:
字符串:ABCABD
前缀为:A、AB、ABC、ABCA、ABCAB
后缀为:D、BD、ABD、CABD、BCABD
有了字符串前缀与后缀的概念,我们就可以计算出一个字符串前缀与后缀的公共子串的最大长度。
KMP算法的具体执行过程:
第一步:
根据公式算出向后移动的位数:移动位数 = 已匹配的字符数 - 最后一个匹配字符的部分匹配值
第二步:
第三步:
第四步:
第五步:
以上的过程可以称为求next数组的过程
void GetNext(char* p,int next[])
{
int pLen = strlen(p);
next[0] = -1;
int k = -1;
int j = 0;
while (j < pLen - 1)
{
//p[k]表示前缀,p[j]表示后缀
if (k == -1 || p[j] == p[k])
{
++k;
++j;
next[j] = k;
}
else
{
k = next[k];
}
}
}
代码实现
#include <stdio.h>
#include <string.h>
void get_next(char s[],int next[]);
int KMP(char s1[],char s2[],int next[]);
int main() {
int i= 0;
int next[1000];
char s2[] = "abcac";
char s1[] = "ababcabcacbab";
get_next(s2,next);
i=KMP(s1,s2,next);
printf("%d\n",i);
return 0;
}
void get_next(char s[],int next[])
{
int len=0;
int i=0;
int j=-1;
next[0]=-1;
len=strlen(s);
while(i<len-1)
{
if(j==-1||s[i]==s[j])
{
i++;
j++;
next[i]=j;
}
else
{
j=next[j];
}
}
}
int KMP(char s1[],char s2[],int next[])
{
int i=0;
int j=0;
int len1=strlen(s1);
int len2=strlen(s2);
while(i<len1&&j<len2)
{
if(j==-1||s1[i]==s2[j])
{
i++;
j++;
}
else
{
j=next[j];
}
}
if(j>=len2)
return i-len2+1;
else
return -1;
}