串
1. 串的定义和实现
字符串简称串,计算机上非数值处理的对象基本都是字符串数据。我们常见的信息检索系统、文本编辑程序、问答系统、自然语言翻译系统等,都是以字符串数据作为处理对象的。
1.1 串的定义
串是由零个或者多个字符组成的有限序列。一般记为S = ‘a1a2a3a4…an’(n>=0).其中S是串名,单引号括起来的字符序列是串的值;ai可以是字母、数字或其他字符;串中字符的个数n称为串的长度。n=0时的串称为空串。
串中任意个连续的字符组成的子序列称为该串的子串,包含子串的串相应地称为主串。某个字符在串中的序号称为该字符在串中的位置。子串在主串中的位置以子串的第一个字符在主串中的位置来表示。当两个串的长度相等且每个对应位置的字符都相等时,称这两个串是相等的。
注意:由一个或多个空格组成的串称为空格串,其长度为串中空格字符的个数
1.2 串的存储结构
1.2.1 定义顺序存储表示
类似于线性表的顺序存储结构,用一组地址连续的存储单元存储串值得字符序列。在串长顺序存储结构中,为每个串变量分配一个固定长度得存储区,既定长数组。
#define MAXLEN 25 //预定义最大串长为255
typedef struct {
char ch[MAXLEN];//每个分量存储一个字符
int length; //串的实际长度
}SString;
串的实际长度只能小于等于MAXLEN,超过预定义长度的串值会被舍去,称为截断。串长有两种表示方法:一是如上述定义描述那样,用一个额外的变量len来存放串的长度;二是在串值后面加一个不计串长的结束标记字符“\0”,此时的串长为隐含值。
在一些串的操作中,若串值序列的长度超过上界MAXLEN,约定用“截断”法处理,要克服这种弊端,只能不限定串长的最大长度,采用动态分配的方式。
1.2.2 堆分配存储表示
堆分配存储表示仍然以一组地址连续的存储单元存放串值的字符序列,但它们的存储空间是在程序执行过程中动态分配得到的。
typedef struct
{
char *ch; //按串长分配存储区,ch指向串的基地址
int length; //串的长度
}HString;
在c语言中,存在一个称之为“堆”的自由存储区,并用malloc()和free()函数来完成动态管理。利用malloc()为每个新产生的串分配一块实际串所需的存储空间,若分配成功,则返回一个指向起始地址的指针,作为串的基地址,这个串由ch指针来表示;若分配失败,则返回NULL,已分配的空间可用free()释放掉。
1.2.3 块链存储表示
类似于线性表的链式存储结构,也可采用链表方式存储串值。由于串的特殊性(每个元素只有一个字符),在具体实现时,每个结点既可以存放一个字符,也可以存放多个字符。每个结点称为块,整个链表称为块链结构。
如下图结点大小为2的链表
1.3 串的基本操作
StrAssign(&T,chars):赋值操作。把串T赋值为chars。
StrCopy(&T,S):复制操作。由串S复制得到串T。
StrEmpty(S):判空操作。若S为空串,则返回TRUE,反则返回FALSE.
StrCompare(S,T):比较操作。若S>T,返回>0;若S=T,则返回值=0;若S<T则返回值<0.
StrLength(S):求串长。返回串S的元素个数。
SubSring(&Sub,S, pos,len):求子串。用Sub返回串S的第pos个字符起长度为len的子串。
Concat(&T,S1,S2):串联接。用T返回由S1和S2联接而成的新串。
Index(S,T):定位操作。若主串S中存在与串T值相同的子串,则返回它在主串S中第一次出现的位置;否则函数值为0.
ClearString(&S):清空操作。将S清为空串。
DestroyString(&S):销毁串。将串S销毁。
不同的高级语言对串的基本操作集可以有不同的定义方法。在上述定义的操作中,串赋值StrAssign、串比较StriCompare、求串长StrLength、串联接Concat及求子串SubString五种操作构成串类型的最小操作子集,即这些操作不可能利用其他串操作来实现;反之,其他串操作(除串清除ClearString和串销毁DestroyString外)均可在该最小操作子集上实现。
2. 串的模式匹配
2.1 简单的模式匹配算法
子串的定位操作通常称为串的模式匹配,它求的是子串(常称模式串)在主串中的位置。这里采用定长顺序存储结构,给出一种不依赖于其他串操作的暴力匹配算法。
int Index(SString S, SString T)
{
int i =1,j= i;
while(i<=S.length && j <=T.length){
if(S.ch[i] == T.ch[j])
{
++i;
++j; //继续比较后继字符
}
else{
i = i-j+2;
j = 1;//指针后退重新开始匹配
}
}
if(j>T.length)
return i-T.length;
else return 0;
}