串
串的逻辑结构
字符串,简称串。
串是由零个或多个字符组成的有限序列。一般记为:
S
=
′
a
1
a
2
.
.
.
a
n
′
(
n
>
=
0
)
S = 'a_1a_2...a_n' (n >= 0)
S=′a1a2...an′(n>=0)
串中字符的个数n称为串的长度。n = 0 时的串成为空串 (用空集符号⌀表示,注意空格串不是空串)
**子串:**串中任意多个连续的字符组成的子序列称为该串的子串,包含子串的串称为主串。
串的逻辑结构和线性表即为相似,区别仅在于串的数据对象限定为字符集。
在基本操作上,串和线性表有很大差别。线性表的基本操作主要以单个元素作为操作对象;而串的基本操作主要以单个元素作为操作对象。
串的存储结构
定长顺序存储表示
类似于线性表的顺序存储结构,用一组地址连续的存储单元存储串值的字符序列。在串的定长顺序存储结构中,为每个变量分配一个固定长度的存储区,即定长数组。
堆分配存储表示
堆分配存储表示仍然以一组地址连续的存储单元存放串值的字符序列,但它们的存储空间是在程序执行过程中动态分配得到的。
定长顺序存储表示和堆分配存储表示通常为高级程序设计语言所采用的串表示方法。
块链存储表示仅作简单介绍。
块链存储表示
类似于线性表的链式存储结构,也可采用链表的方式存储串值。由于串的特殊性(每个元素只有一个字符),在具体实现时,每个结点既可以存放一个字符,也可以存放多个字符。每个结点称为块,整个链表称为块链结构。
串的模式匹配算法
子串的定位操作通常称为串的模式匹配,它求的是子串(通常称为模式串)在主串中的位置。
简单的模式匹配算法
这是一种暴力匹配算法,它的最坏时间复杂度为O(nm),其中n和m分别为主串和模式串的长度。
KMP算法
KMP算法的时间复杂度为O(n+m).
考虑到,当模式串部分匹配时,在子串中被部分匹配的字符已经查看过了,没有必要再回溯查看。
我们将思路从回溯主串改为回溯模式串。
**next[]数组:**当模式串的第 j 个字符匹配失败时,令模式串跳到next[j]再继续匹配。
对于任何一个next[]数组,都有next[1] = 0
求模式串的next数组
引入两个概念:
**串的前缀:**包括第一个字符,且不包括最后一个字符的子串。
**串的前缀:**包括最后一个字符,且不包括第一个字符的子串。
当第 j 个字符匹配失败,由前1~j-1个字符组成的串记为S,则:
next[j] = S的最大相等前后缀长度 + 1
特别的,next[1] = 0,经过计算,next[2]也恒等于1
KMP算法的优化
在next[]数组的比较中有时会多进行一次无意义的比较,比如下图这种情况:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
使用next[]数组,发现j = 4时,模式串不匹配,j转为next[4],即为1,则此时比较字符 I 和字符 g ,但是我们其实已经知道主串的 i 位置是 I ,所以再将 I 和 g 做对比是多余的。
改进后的数组我们叫做nextval[]。
我们规定nextval[1] = 0.
怎么求nextval[]数组?
- 先求出模式串的next[]数组
- 从左往右填写nextval[]数组,若模式串在 j 位置不匹配, j 所指的字符为 x,next[j]所指的字符为 y
- 若x = y ,则nextval[j] = nextval[next[j]];若 x != y ,则nextval[j] = next[j]
- 依次类推,直到填写完nextval[]
王道考研对KMP算法的总结:
] = nextval[next[j]];若 x != y ,则nextval[j] = next[j]
4. 依次类推,直到填写完nextval[]
王道考研对KMP算法的总结: