学习时间
2021-01-18
学习内容
字符串的基本概念
字符串是一种特殊的线性表,其数据元素限定为字符集。它由零个或多个字符组成,表达式形如 String s=“123”;
其中
- s是字符串的名字
- 双引号括起来的字符序列是字符拆的值,引号本身不属于字符串
- 双引号之内的可以是数字、字母、字符等
- 双引号里字符的个数就是字符串的长度
常用术语:
- 空串:长度为0.不包含任何字符
- 空格串:仅有一个或者多个空格组成,长度大于等于一
- 字串:任意个连续字符组成的子序列就是一个串的子串
- 主串:包含子串的串就是主串
- 前缀子串:比如"123"是"12345"的前缀子串
- 后缀子串:比如"345"是"12345"的后缀子串
- 串相等:当且仅当两个串完全相同时,说明两个串相等
- 模式匹配:子串在主串中出现的第一个位置的运算就是串的模式匹配。这时,主串也叫目标串,子串也叫模式串。
且从上面的叙述可以看出,空串是任意串的子串,任意串也是自身的子串
字符串的运算
详见
StringBuffer类
String类
在这两篇博客中,本人有关于在Java中字符串运算的详细演示。
字符串的存储结构及实现
定长顺序串
串的定长顺序存储结构是用一组地址连续的存储单元存储串的字符序列,也称为“静态存储分配的顺序串”。
定长顺序存储直接使用定长的字符数组定义,为每个定义的串变量分配一个固定长度的存储区,存储分配在编译时完成。
在对定长顺序串进行操作时,可能出现“串截断”现象。为了避免这种现象,我们可以不限定串的最大长度,即动态分配串值的存储空间。
堆串
串的堆存储结构也是用地址连续的存储单元存储串的字符序列,不同的是,堆串的存储空间时在程序执行过程中动态分配的。在整个系统中存在一个称为“堆”的自由存储区。在每当建立一个新串时都可以通过动态分配函数从这个空间中分配一块实际所需的存储空间,用来存储新的串。所以只要存储空间分配成功,在操作的过程中就不会发生“截断”。
块链串
因为串是一种特殊的线性表,所以我们可以用链式存储结构存储串。这时,链表的每一个结点既可以存储一个字符,也可以存储多个字符。每一个结点称为块,整个链表称为块链结构。
存储密度
存储密度=(串值所占的存储位)/(实际分配的存储位)
串的模式匹配
我们用BF算法和KMP算法演示
BF算法
算法思想:
BF算法也叫“蛮力算法”。比如在主串的第n个位置上第一次处出现了模式串的第一个字符。那么就从这个位置开始,一个一个的跟后面字符比较,以此类推,直到后面的都相同,说明匹配成功。否则,哪怕只有一个不相等也不成功。
算法分析:
BF算法思想十分简单,但在最坏的情况下,算法的时间复杂度为O(m*n),其中n和m分别是主串和模式串的长度。
KMP算法
算法思想:我们可以在匹配的第一个字符的时候,采取将模式串的几个字符同时和主串的字符进行比较,这样就可以减少比较的次数,从而降低时间复杂度。
算法分析:
KMP算法的时间复杂度为O(m+n)
两个算法的对比
虽然BF算法的时间复杂度为O(m*n),但是在实际执行的过程中,m往往是远远小于n的,所以其时间复杂度近似等于O(m+n),至今仍被采用。所以说KMP算法在模式串和主串之间存在很多“部分匹配成功”的时候,才显得比BF算法优越。KMP算法最大的特点是主串指针不需要回溯,整个过程中,主串只需要从头到尾扫描一次,对于处理从外设输入的庞大文件很有效。
总结
- 字符串是一种特殊的线性表,其特殊性在于组成线性表,其特殊性在于组成线性表的数据元素仅是一个单字符
- 字符串常用的存储方式有定长顺序串、堆串、块链串三种
- 顺序串是以一维数组作为存储结构,其运算实现方法类似于线性表的顺序存储结构
- 堆串是以动态一维数组作为存储结构,其运算实现方法和顺序串在存储管理上有所不同
- 块链串是以链表作为存储结构,其运算实现方法类似于链表
- 串的模式匹配算法:BF模式匹配算法处理思路简单,但由于需要进行失配后主串回溯处理,所以时间复杂度较高;KMP模式匹配算法消除了失配之后的回溯,所以匹配速度较快。