串的定义和操作
定义
==串是限定了元素为字符的线性表==
串增删改查通常以子串为操作对象,而线性表主要针对表内的某一个元素
串的存储结构
- 顺序存储:
最大长度为10 - 链式存储:
每个节点一个or多个字符
模式匹配
- 基本概念:
子串:一定是在主串中存在的才叫子串
模式串:尝试在主串中找的串,未必存在
模式匹配:在主串中找到与模式串相同的子串,并返回其位置
朴素模式匹配
- 思路:
主串中与模式串长度相同的所有子串搞出来,挨个与模式串对比,有一个字符不匹配时,立即放弃当前子串,转而索引下一个子串 - 代码实现:
KMP算法
- 引入原因:
在朴素模式匹配算法最坏的情况中,主串指针向前走m步,回退m-1步,模式串也不断在回退,导致算法时间复杂度很高
只有在子串与模式串经常能部分匹配的时候,kmp才比朴素模式匹配优秀很多,其实也没有优秀很多 - 思路:
让主串不会退,每轮比较只回退模式串的指针
用next数组来标记模式串回退的位置,j=k且发现字符不匹配时,模式串指针回溯到j=next[k] - KMP代码
int INDEX_KMP(SString S,SString T,int next[]){
int i= 1,j=1;
while(i<=S.length&&j<=T.length){
if (j==0||S.ch[i]==T.ch[j]){
//注意j=0时,在最开始的位置就不匹配,此时i++,j++(因为规定next[1]=0)
++i;
++j;
}
else
j=next[j];//模式串向右移动
}
if(j>T.length)
return i-T.length;//匹配成功
else
return 0;
}
#### 求一个模式串的next数组
串的前缀 | 包含第一个字符但不包含最后一个字符的子串 |
---|---|
串的后缀 | 包含最后一个字符但是不包含第一个字符的子串 |
==当第j个字符匹配失败,由前j-1个字符组成的串记为S:== |
- next[j] = S最长相等的前后缀长度+1
- 前后缀是正着比较的,注意相等的前后缀可以有部分重叠
- S为空,则next【j】等于0
- S没有重叠的前后缀,next[j]等于1
- 但是注意这个前后缀是不能完全重叠的,最起码也要差一个(就是前后缀的定义)
next[0]=空,
next[1]=0,
next[2]=1:前面只有一个字符
如果next【j】不等于0, i保持不动,j按照next回溯
如果next【j】等于0, i++,j++(也就是j=1) 模式串的第一个字符与主串i位置不匹配
KMP优化
1. 用nextval替代next,减少重复的比较
2. 确定nextval[j]的办法
![在这里插入图片描述](https://ucc.alicdn.com/images/user-upload-01/96d6dc0f826c4fd4b48d34b1af12736e.png?x-oss-process=imagewatermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5LiN5pmaeA==,size_20,color_FFFFFF,t_70,g_se,x_16)
next数组的那个数所对应的S字符如果和目前S的字符一样,那就把前面那个的nextval的值抄过去
![在这里插入图片描述](https://ucc.alicdn.com/images/user-upload-01/dc1d0113093a4102b9878074991a12e8.png?x-oss-process=imagewatermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5LiN5pmaeA==,size_20,color_FFFFFF,t_70,g_se,x_16)
==如果两个字符不一样,那就把目前字符的next数组抄下去==
**nextval[1]是一直等于0的**