第6章串数组:串的定义和存储结构
第 6 章 串、数组
6.1 串的定义和存储结构
6.1.1 串的定义
串(String)或字符串是由零个或多个字符组成的有限序列。
一般记作:
s="a1a2⋯an" (n≥0)
s = ^"a_1a_2\cdots a_n^"~(n\ge0)
s="a1a2⋯an" (n≥0)
其中:
- sss 是串的名;
- 用双引号或单引号括起来的字符序列是串的值。注意:引号不是串的内容,是串的标志,用于将串与标识符(如变量名称等)加以区别。
- ai (1≤i≤n)a_i~(1\le i\le n)ai (1≤i≤n) 代表一个字符,比如英文字母、数字、常用的标点符号以及空格等各种合法字符。
- 串中字符的数目 nnn 称为串的长度。
- 零个字符的串称为空串,通常用 ϕ\phiϕ 表示。空串的长度为零。
串中任意个连续的字符组成的子序列称为该串的子串。包含子串的串相应地称为主串。
通常,称字符在序列中的序号为该字符在串中的位置。子串在主串中的位置以子串的第一个字符在主串中的位置来表示。
两个串相等,当且仅当两个串的值相等,即:两个串的长度相等并且对应位置上的字符都相等。
串的逻辑结构和线性表极为相似,区别仅在于串的数据对象约束为字符集。另外,串的基本操作和线性表有很大差别:
- 在线性表的基本操作中,大多以“单个元素”作为操作对象,例如,在线性表中查找某个元素,求取某个元素,在某个位置上插入一个元素或删除一个元素等;
- 在串的基本操作中,通常以“串的整体”作为操作对象,例如,在串中查找某个子串,求取一个子串,在串的某个位置上插入一个子串,以及删除一个子串等。
6.1.2 串的存储结构
1. 串的顺序存储
串的顺序存储结构,即用一组地址连续的存储单元存储串值的字符序列。按照预定义的大小,为每个定义的串变量分配一个固定长度的存储区,这样就构造了串的定长顺序存储结构。
//串的定长顺序存储结构
#define MAXLEN 255 //串的最大长度typedef struct{char ch[MAXLEN+1]; //存储串的一维数组int length; //串的当前长度
}SString;
MAXLEN
表示串的最大长度;ch
是存储字符串的一维数组,每个分量存储一个字符(以ch[MAXLEN+1]
定义数组,意味着从下标为 1 的数组分量开始存储的,下标为 0 的分量闲置不用);length
表示当前字符串的长度。
串的定长顺序存储结构,是静态的定义方式,在编译时已确定了串空间的大小。
此外,C 语言中,提供了另外一种利用堆实现的顺序存储结构。这种存储结构可以为每个新生成的串动态分配一块实际串长所需的存储空间,称之为串的堆式顺序存储结构。
//串的堆式顺序存储结构
typedef struct{char *ch; //若是非空串,则按串长分配存储区,否则 ch 为 NULLint length;
}HString;
关于串的基本操作,和顺序表类似,所以不作为重点。
2. 串的链式存储
一般,采用单链表作为串的链式存储方式。
由于串结构中的每个数据元素是一个字符,在用链表存储串值时,就存在一个“结点大小”的问题,即每个结点可以存放一个字符,也可以存放多个字符。
例如,图 6.1.1(a) 所示为结点大小为 4(即每个结点存放 4 个字符)的链表,图 6.1.1(b) 所示为结点大小为 1 的链表。
当结点大小大于 1 时,由于串长不一定是结点大小的整倍数,则链表中的最后一个结点不一定全被串值占满,此时通常补上“#
”或其他的非串值字符(通常“#
”不属于串的字符集,是一个特殊的符号)。
为了便于进行串的操作,当以链表存储串值时,除了头指针外,再附设一个尾指针指示链表中的最后一个结点,并且给出当前串的长度。这种串存储结构称为块链结构。
//串的链式存储结构
#define CHUNKSIZE 80 //可由用户定义的块大小typedef struct Chunk{char ch[CHUNKSIZE];struct Chunk *next;
}Chunk;typedef struct{Chunk *head, *tail; //串的头和尾指针int length; //串的当前长度
}LString;
当串采用链式存储结构时,它的各项操作类似于链表,所以此处不详细讨论。