第四章 串
计算机上非数值处理的对象基本上是字符串数据。
在不同类型的应用中,字符串具有不同的特点,要有效的实现字符串的处理,必须选用合适的存储结构。
4.1 串类型的定义
串 String 由零个或多个字符组成的有限序列。
s = 'a1a2a3...an' n >= 0
s 串名
用单引号扩起来的字符序列是串的值
n 串的长度
空串:零个字符的串
子串:串中任意个连续字符组成的子序列称为该串的字串
位置:字符在序列中的序号称为该字符在串中的位置
相等:当且仅当两个串的值相等
串的逻辑结构与线性表极为相似,区别仅在于串的数据对象约束为字符集。
最小操作子集: 串赋值求串长 求子串 串比较 串连接
4.2 串的表示和实现
串的三种表示方法:
1、定长顺序存储表示
用一组连续的存储单元存储串值的字符序列,此时串的最大长度被限定。
两种表示方法:
1以下标为0的数组分量存放串的实际长度 PASCAL
2在串值后面加一个不计入串长的结束标记字符,此时串长为隐含值 C语言中的'\0'
2、堆分配存储表示
在C语言中,存在一个称之为“堆”的自由存储区,由动态分配函数malloc()和free()管理。
仍以一组连续的存储单元存储串值的字符序列,此时串的长度无限制。
存储空间在程序执行过程中动态分配。
3、块链存储表示
块大小的选择
头指针 尾指针串长度
设置尾指针的目的:联结操作
4.3 串的模式匹配算法
串的模式匹配:字串的定位操作。
KMP算法: O(n+m)
改进:每当一趟的匹配过程中出现字符比较不等时,不需要回溯i指针,而是利用已经得到的“部分匹配”的结果将模式向右“滑动”尽可能远的一段距离后,继续进行比较。
匹配仅需从模式中第k个字符与主串中第i个字符继续进行比较:此时模式中头k-1个字符和主串中最后k-1个字符相同。
亦即 next[1, j-1] 这个串中,前后缀相同串的字符为 next[1, next[j] - 1],所以下一次比较的是next[j]个字符的不同。
next数组里存放的,相同前后缀子串,前子串位置的下一个位置坐标。
next[j] = k : 当模式中第j个字符失配时,重新进行比较的位置。
算法:
假设主串指针i = pos,模式串指针j = 1;
若si = pj,则i++, j++;
否则j = next[j], 继续进行si 和pj 的比较。
如果 j = 0, 则 i++, j++, 继续进行si和 pj的比较。
KMP算法的基础是next函数值,仅和模式串本身有关。
求next[j + 1] 的方法:
next[1] = 0;
next[j] = k;
若 pk = pj,next[j + 1] = k +1;
若 pk!=pj,k = next[k],继续进行pk和 pj的比较。若k = next[k] = 0,则next[j + 1] = 1。
i = 1;
next[1] = 0;
j = 0;
while (i < length)
{if (j == 0 || T[i] == T[j])i++; j++; next[i] = j;elsej = next[j];
}
两点说明:
1、简单算法的时间复杂度虽然是O(n*m),但在一般情况下,其实际执行时间近似于O(n+m),因此至今仍被采用。
KMP算法仅当模式与主串之间存在许多“部分匹配”的情况下才显得比简单算法快得多。
KMP算法的最大特点:无需回溯,整个匹配过程,对主串仅需从头至尾扫描一遍,这对处理从外设输入的庞大文件很有效,可以边读入边匹配,而无需回头重读。
2、next函数的修正算法 针对连续字符的改进
i = 1;
next[1] = 0;
j = 0;
while (i < length)
{if (j == 0 || T[i] == T[j])i++; j++;if (T[i] != T[j]) next[i] = j;else next[i ] = next[j];elsej = next[j];
}
4.4 串操作应用举例:
文本编辑
文本编辑程序是一个面向用户的系统服务程序,文本编辑的实质是修改字符数据的形式或格式。
虽然各文本编辑程序的功能强弱不同,但基本操作是一致的,一般包括串的查找、插入、删除等。
可以利用换页符和换行符把文本划分为若干页,每页有若干行。
把文本看成是一个字符串,称为文本串。页是文本串的子串,行是页的子串。
为了管理文本的页和行,在进入文本编辑的时候,编辑程序先为文本串建立相应的页表和行表,即建立各子串的存储映像。
页表的每一项给出页号和该页的起始行号。
行表的每一项指示行号、起始地址和该字串的长度。
设立页指针、行指针、字符指针,分别指向当前操作的页、行、字符。
页表和行表是递增顺序存储的,对行表进行的插入或删除运算需移动操作位置以后的全部表项。
Tip:由于访问是以页表和行表作为索引的,所以在作行和页的删除操作时,可以只对行表和页表作相应的修改,不必删除所涉及的字符,这样可以节省时间。
建立词索引表
信息检索。
可设定此索引表为按字典有序的线性表。
重复下列操作直至文件末尾:
1、从书目文件中读取一个书目串;
2、从书目串中提取所有关键词插入词表;
3、对词表中的每一个关键词,在索引表中进行查找并作相应的插入操作。
需要一张常用词表,不在常用词表中的字符串为关键字。
索引表虽是动态生成,在生成过程中需频繁进行插入操作,但考虑索引表主要为查找用,为了提高查找效率,宜采用顺序存储结构。
索引表内容:关键词 + 书号索引。
书号索引采用链式存储结构。