More Related Content More from Wang Yizhe (13) 第四章 串1. 第四章 串
4.1 串类型的定
义
4.2 串的表示和实现
4. 空串:不含任何字符的串,串长度为
0,
用“ ” 或 ‘ ’ 表示。
空格串:仅由一个或多个空格组成的
串,
长度为串中空格字符的
个数。
如: ‘ ’ , C= ‘ BEI JING ’
子串:由串中任意个连续的字符组成
的
6. 串的抽象数据类型定义
ADT String {
数据对象:
D = { ai |ai∈ CharacterSet,
i=1,2,...,n, n≥0 }
数据关系:
R1 = { < ai-1, ai > | ai-1, ai ∈ D,
i=2,...,n }
基本操作:
……
} ADT String
7. StrAssign (&T, chars) // 串赋值
初始条件: chars 是字符串常量。
操作结果:把 chars 赋为 T 的值。
StrCopy (&T, S) // 串复制
初始条件:串 S 存在。
操作结果:由串 S 复制得串 T 。
DestroyString (&S)
初始条件:串 S 存在。
操作结果:串 S 被销毁。
8. ClearString (&S)
初始条件:串 S 存在。
操作结果:将 S 清为空串。
StrEmpty (S)
初始条件:串 S 存在。
操作结果:若 S 为空串,则返回
TRUE ,否则返回 FALSE 。
9. StrCompare (S, T) // 串比较
初始条件:串 S 和 T 存在。
操作结果:若 S>T ,则返回值 >0 ;
若 S=T ,则返回值 =0 ;
若 S<T ,则返回值 <0 。
StrCompare(‘data’, ‘structure’) <0
字符串的比较规则 : 对两个字符串自左至右逐
个字符相比 ( 按 ASCII 码值大小 ), 直到出现不
同字符或遇到结束符为止 . 如全部字符相同则
认为相等 ; 若出现不相同的字符 , 则以第一个
不相同的字符的比较结果为准 , 如上
例 “ d”<“s”. 因此比较结果小于 0 。
11. Concat (&T, S1, S2) // 串联接
初始条件:串 S1 和 S2 存在。
操作结果:用 T 返回由 S1 和 S2
联接而成的新串。
Concat(&T,‘data’, ‘structure’)
T=‘datastructure’
12. SubString (&Sub, S, pos, len) // 求子串
初始条件:串 S 存
在, 1≤pos≤StrLength(S) 且
0≤len≤StrLength(S)-pos+1 。
操作结果:用 Sub 返回串 S 的第 pos 个
字符起长度为 len 的子串。
SubString(&sub, ‘data structure’, 6, 9)
Sub=‘structure’
13. Index (S, T, pos) // 串定位
初始条件:串 S 和 T 存在, T 是非空串,
1≤pos≤StrLength(S) 。
操作结果:若主串 S 中存在和串 T 值相同
的子串 , 则返回它在主串 S 中第 pos 个字符之
后第一次出现的位置 ; 否则函数值为 0 。
假设: S = ′abcaabcaaabc′, T = ′bca′
Index(S, T, 1) = 2 ;
Index(S, T, 3) = 6 ;
Index(S, T, 8) = 0 ;
14. Replace (&S, T, V) // 串替换
初始条件:串 S,T 和 V 存在, T 是非
空串。
操作结果:用 V 替换主串 S 中出现
的所有与 T 相等的不重叠的子串。
例如: S=‘abcaabc’, T=‘ab’, V=‘x’
S=‘xcaxc’
V=‘bc’
S=‘bccabcc’
15. StrInsert (&S, pos, T)
初始条件:串 S 和 T 存在,
1≤pos≤StrLength(S) + 1 。
操作结果:在串 S 的第 pos 个字符之
前插
例如: S =‘ god’ , T 。
入串 StrInsert ( & S,
2, ‘o’)
S=‘good’
16. StrDelete (&S, pos, len)
初始条件:串 S 存在,
1≤pos≤StrLength(S)-len+1 。
操作结果:从串 S 中删除第 pos 个字符
起
长度为 len 的子串。
例如 : S= ‘structure’ ,
StrDelete( & S, 1, 5)
S=‘ture’
18. 在以上操作中,
串赋值 StrAssign 、串复制 Strcopy 、
串比较 StrCompare 、求串长
StrLength 、串联接 Concat 、求子串
SubString
6 种操作构成串类型的最小操作子集,
即:这些操作不可能利用其他串操作来
实现,反之,其他串操作(除串清除
ClearString 和串销毁 DestroyString 外)
可在这个最小操作子集上实现。
19. 例如,可利用串比较、求串长和求子
串 等操作实现定位函数 Index(S, T,
pos) 。
算法的基本思想为
:
StrCompare(SubString(S, i, StrLength(T)), T) = = 0
i
S 串
pos T 串 n-m+1 T 串
在主串 S 中取出从第 i 个字符起,长度和串 T 相等的子串和串 T
进行比较,若相等,则求得函数值为 i ;否则 i 值增 1 直至串 S 中不存在
和串 T 相等的子串为止。
20. int Index (String S, String T, int pos) {
// T 为非空串。若主串 S 中第 pos 个字符之后存在与 T 相等的子
则返回第一个这样的子串在 S 中的位置,否则返回 0
if (pos > 0) {
n = StrLength(S); m = StrLength(T); i = pos;
while ( i <= n-m+1) {
SubString (sub, S, i, m); // 从 S 中取子串置于 sub 中
if (StrCompare(sub,T) != 0) ++i ;
else return i ;
} // while
} // if
return 0; // S 中不存在与 T 相等的子串
} // Index
21. C++ 中的 String 类
C++ 标准类库将面向对象串的概念加入到 C+
+ 语言中。串类封装了类的属性,并提供了一
系列允许访问这些属性的服务。例如: String
类的一些主要的成员函数有:
string append(const char *s); // 将字符串 s 加在本串尾
string assign(const char *s); // 赋值
Int compare(const string& str); // 比较本串与 str 中串的大小
string insert(int p0, const *s);
// 将 s 所指向的字符串插入本串位置 p0 之
前
24. 4.2.1 定长顺序存储表示
用一组地址连续的存储单元存储串
值的字符序列,类似于线性表的顺序存储
结构。所谓定长顺序存储结构,是直接使
用定长的字符数组来定义,数组的上界预
先给出:
#define MAXSTRLEN 255
// 用户可在 255 以内定义最大串
长
typedef unsigned char
SString[MAXSTRLEN + 1];
26. 1 .串联结
Contcat ( &T,S1,S2 )
S1 [ 0 S2 [ 0
] ]
S1 S2
T
T[0] MAXSTRLEN
S1[0]+S2[0] <= MAXSTRLEN
27. S1 [ 0 S2 [ 0
] ]
S1 S2
S2 中被截去的
T 字符序列
T[0] MAXSTRLEN
S1[0] < MAXSTRSIZE 而 S1[0]+S2[0] > MAXSTRSIZE
28. S1 [ 0 S2 [ 0
] ]
S1 S2
T
S2 串被全部截
去
T[0] MAXSTRLEN
S1[0] = MAXSTRLEN
29. Status Concat(SString S1, SString S2, SString &T) {
if (S1[0]+S2[0] <= MAXSTRLEN) { // 未截断
T[1..S1[0]] = S1[1…S1[0]];
T[S1[0]+1…S1[0]+S2[0]] = S2[1…S2[0]];
T[0] = S1[0]+S2[0]; uncut = TRUE;}
else if (S1[0] < MAXSTRSIZE) { // 截断
T[1…S1[0]] = S1[1…S1[0]];
T[S1[0]+1…MAXSTRLEN]=S2[1…MAXSTRLEN - S1[0]];
T[0] = MAXSTRLEN; uncut = FALSE;}
else { S1[0] = MAXSTRSIZE // 截断 ( 仅取 S1)
T[0...MAXSTRLEN] = S1[0…MAXSTRLEN];
// T[0] == S1[0] == MAXSTRLEN
uncut = FALSE; }
return uncut;
} // Concat
30. 2 .求子串 SubString(&Sub, S, pos, len)
Status SubString(SString&Sub, SString S, int
pos,int len) {
// 用 Sub 返回串 S 的第 pos 个字符起长度为 len 的子串。其
中 1≤pos ≤StrLength(S) 且 0≤len≤StrLength(S)-pos+1
if (pos<1 ||pos>S[0] || len<0 || len>S[0]-pos+1)
return ERROR;
Sub[1……len]=S[pos…pos+len-1] ;
Sub[0]=len ;
return OK;
} // SubString
31. 定长顺序存储表示的特点与问题
1 . 实现串操作的原操作为“ 字符序列的复制” ,操
作的时间复杂度基于复制的字符序列的长度。
2. 在操作中出现串值序列的长度超过 MaxS trLe n
时,约定用截尾法处理,这种情况可能在联结串
或插入 , 置换时发生。
3. 克服这个问题惟有不限定串长的最大长度,即
动态分配串值的存储空间。
32. 4.2.2 堆分配存储表示
以一组地址连续的存储单元存储串值的字符序
列,存储空间在程序执行过程中动态分配。
C 语言中提供的串类型就是以这种存储方式实
现的。系统利用函数 m allo c () 和 fre e ( ) 进行串值空
间的动态管理,为每一个新产生的串分配一个存储
区,称串值共享的存储空间为“ 堆”。
C 语言中的串以一个空字符为结束符,串长是
一个隐含值。
33. typedef struct {
char *ch; // 若是非空串,则按串长分
配存储区 , 否则
ch 为 NULL
int length; // 串长度
} HString;
这类串操作实现的算法为:
先为新生成的串分配一个存储空间,然后进行
串值的复制。
34. 1. 串赋值
Status StrAssign(Hstring&T,char*chars){
// 生成一个其值等于串常量 chars 的串 T
If ( T.ch ) free (T.ch); // 释放 T 原有空间
for(i=0,c=chars; c; ++i,++c); // 求 chars 的长度
i
If ( !i ) {T.ch=NULL; T.length=0;}
else{
if(!(T.ch=(char*)malloc(i*sizeof(char))))
exit(OVERFLOW); // 开辟空间再赋值
T.ch[0…i-1]=chars[0…i-1]; T.length=i; }
return OK;
35. 2. 串比较 ;
Int StrCompare(Hstring S,Hstring T){
for(i=0; i<S.length && i<T.length; ++i)
if ( S.ch[i] != T.ch[i] )
Return S.ch[i]-T.ch[i];
Return S.length - T.length
// 若 S>T, 则返回值 >0; 若 S=T, 则返回值 =0 ;
若 S<T ,则返回值 =0
} // StrCompare
36. 3. 串联接
Status Concat(Hstring&T,HStringS1,HstringS2)
{ // 用 T 返回由 S1 和 S2 联接而成的新串
if(T.ch) free(T.ch); // 释放旧空间
if(!(T.ch=(char*)malloc((S1.length+S2.length)*
sizeof(char)))) exit(OVERFLOW);
T.ch[0…S1.length - 1]= S1.ch[0…S1.length - 1];
T.length= S1.length+ S2.length;
T.ch[S1.length…T.length-1]=S2.ch[0…S2.length-1];
return OK;
} // Concat
37. 4. 取子串
Status SubString(HString&Sub,Hstring S,int pos,int len)
{ // 用 Sub 返回串 S 的第 pos 个字符起长度为 len 的子串。
// 其中 1≤pos StrLength(S) 且 0≤ len≤ StrLength(S)-pos+1
if (pos<1 ||pos>S.length || len<0||len>S.length-pos+1)
return ERROR;
if(Sub.ch) free(Sub.ch); // 释放旧空间
if (!len){ Sub.ch=NULL; Sub.length=0; } // 空子串
else { // 完整子串
Sub.ch= (char*) malloc (len*sizeof(char));
// 取长度 len 分配空
间
Sub.ch[0…len-1]=S.ch[pos-1…pos+len-2] ;
Sub.length=len ;
return OK;
38. 4.2.3 块链存储表示
以链表存储串值,除头指针外还可
以附设一个尾指针指示链表中的最后一
个结点,并给出当前串的长度。称如此
定义的串存储结构为 块链结构。 结点大小
块链结构
39. #define CHUNKSIZE 80 // 可由用户定义的块大小
typedef struct Chunk { // 结点结构
char ch[CUNKSIZE];
struct Chunk *next;
} Chunk;
typedef struct { // 串的链表结构
Chunk *head, *tail; // 串的头和尾指针
int curlen; // 串的当前长度
} LString;
41. 存储密度的大小直接影响着串处理的效
率.
1. 存储密度小 , 运算处理方便 , 但存储占用
量大 .
2. 存储密度小 , 在串处理过程中需要进行内
外存交换的话 , 会因为内外存交换操作过
多而影响处理的总效率 .
串值的链式存储结构对于某些串操作
有一定方便处 , 但总的说来不如另外两种存
储结构灵活 , 它占用存储量大且操作复杂 .
42. 练习 : 设 s=‘I AM A
STUDENT’ , t=‘GOOD’ ,
q=‘WORKER’ ,求:
( 1 ) StrLength(s) , StrLength(t)
( 2 ) SubString(s, 8, 7) , SubString(t, 2, 1)
( 3 ) Index(s, ‘A’,1) , Index(s,t,3)
( 4 ) Replace(s, ‘STUDENT’, q)
( 5)
Concat(SubString(s,6,2),Concat(t,SubString(s,7,8)))