第四章    串
 4.1 串类型的定
 义
4.2 串的表示和实现
学习提要:
 1. 熟悉串的基本操作的定义,并能利用这
些
基本操作来实现串的其它各种操作的方法
。
 2. 熟练掌握在串的定长顺序存储结构上实
现串的各种操作的方法。
 3. 掌握串的堆分配存储结构以及在其上实
现串操作的基本方法。
4. 了解串的块链存储结构。
重难点内容:
 串的存储结构
§4.1 串类型的定义
基本概念

串( string ):由零个或多个字
符组成的有限序列,也称字符串。
记为:
    S = ‘a1a2a3……an’ (n≥0)

         如: A= ‘BEIJING’ ,   B=
‘JING’
空串:不含任何字符的串,串长度为
0,
         用“    ” 或 ‘ ’ 表示。
空格串:仅由一个或多个空格组成的
串,
          长度为串中空格字符的
个数。
  如: ‘   ’ ,    C= ‘ BEI JING ’
子串:由串中任意个连续的字符组成
的
字符在串中的位置:字符在序列中的
序号。
子串在主串中的位置:以子串的第一
个字符在主串中的位置来表示。
 如: A= ‘ BEIJING ’ , B= ‘JING ’ ,
   B 在 A 中的位置为 4 。
 串相等:当且仅当两个串的值相等。
也就是说,只有两个串的长度相等且各
个对应位置的字符都相等时才相等。
串的抽象数据类型定义
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
StrAssign (&T, chars) // 串赋值
    初始条件: chars 是字符串常量。
    操作结果:把 chars 赋为 T 的值。
StrCopy (&T, S) // 串复制
     初始条件:串 S 存在。
     操作结果:由串 S 复制得串 T 。
DestroyString (&S)
     初始条件:串 S 存在。
     操作结果:串 S 被销毁。
ClearString (&S)
    初始条件:串 S 存在。
   操作结果:将 S 清为空串。
StrEmpty (S)
    初始条件:串 S 存在。
      操作结果:若 S 为空串,则返回
 TRUE ,否则返回 FALSE 。
StrCompare (S, T) // 串比较
 初始条件:串 S 和 T 存在。
 操作结果:若 S>T ,则返回值 >0 ;
           若 S=T ,则返回值 =0 ;
           若 S<T ,则返回值 <0 。

  StrCompare(‘data’, ‘structure’) <0
字符串的比较规则 : 对两个字符串自左至右逐
个字符相比 ( 按 ASCII 码值大小 ), 直到出现不
同字符或遇到结束符为止 . 如全部字符相同则
认为相等 ; 若出现不相同的字符 , 则以第一个
不相同的字符的比较结果为准 , 如上
例 “ d”<“s”. 因此比较结果小于 0 。
StrLength (S) // 求串长
 初始条件:串 S 存在。
   操作结果:返回 S 的元素个数
,称为串的长度。
Concat (&T, S1, S2) // 串联接
 初始条件:串 S1 和 S2 存在。
  操作结果:用 T 返回由 S1 和 S2
 联接而成的新串。
 Concat(&T,‘data’, ‘structure’)

    T=‘datastructure’
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’
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 ;
Replace (&S, T, V) // 串替换
 初始条件:串 S,T 和 V 存在, T 是非
空串。
  操作结果:用 V 替换主串 S 中出现
的所有与 T 相等的不重叠的子串。
例如: S=‘abcaabc’, T=‘ab’, V=‘x’
      S=‘xcaxc’
      V=‘bc’
      S=‘bccabcc’
StrInsert (&S, pos, T)
 初始条件:串 S 和 T 存在,
       1≤pos≤StrLength(S) + 1 。
  操作结果:在串 S 的第 pos 个字符之
 前插
例如: S =‘ god’ , T 。
               入串 StrInsert ( & S,
2, ‘o’)
          S=‘good’
StrDelete (&S, pos, len)
  初始条件:串 S 存在,
      1≤pos≤StrLength(S)-len+1 。
   操作结果:从串 S 中删除第 pos 个字符
 起
              长度为 len 的子串。
 例如 : S= ‘structure’ ,
         StrDelete( & S, 1, 5)
         S=‘ture’
对于串的基本操作集可以有不同的
 定义方法,在使用高级程序设计语言中的
 串类型时,应以该语言的参考手册为准。
例如: C 语言函数库中提供下列串处理函数:
                       K 的作用是将 s tr2 中前
 gets(str) 输入一个串;      k 个字符复制到 s rt1 中
 puts(str) 输出一个串;      去,取代 s tr1 中最前面
                       k 个字符。
 strcat(str1, str2) 串联接函数;
 strcpy(str1, str2, k) 串复制函数;
 strcmp(str1, str2) 串比较函数;
 strlen(str) 求串长函数;
在以上操作中,
串赋值 StrAssign 、串复制 Strcopy 、
串比较 StrCompare 、求串长
StrLength 、串联接 Concat 、求子串
SubString
6 种操作构成串类型的最小操作子集,
即:这些操作不可能利用其他串操作来
实现,反之,其他串操作(除串清除
ClearString 和串销毁 DestroyString 外)
可在这个最小操作子集上实现。
例如,可利用串比较、求串长和求子
串 等操作实现定位函数 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 相等的子串为止。
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
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 之
前
串的逻辑结构和线性表极为相
似,区别仅在于串的数据对象约束为
字符集。
 串的基本操作和线性表有很大差
别。
  在线性表的基本操作中,大多以“
单个元素 ” 作为操作对象;
  在串的基本操作中,通常以“ 串的
整体 ” 作为操作对象。
§4.2 串的表示和实现
4.2.1 串的定长顺序存储表示

4.2.2 串的堆分配存储表示

4.2.3 串的块链存储表示
4.2.1 定长顺序存储表示
   用一组地址连续的存储单元存储串
值的字符序列,类似于线性表的顺序存储
结构。所谓定长顺序存储结构,是直接使
用定长的字符数组来定义,数组的上界预
先给出:
 #define MAXSTRLEN 255
              // 用户可在 255 以内定义最大串
 长
 typedef unsigned char
         SString[MAXSTRLEN + 1];
特点 :
串的实际长度可在这个予定义长
度的范围内随意设定,超过予定义
长度的串值则被舍去,称之为“ 截
断” 。
按这种串的表示方法实现的串的
运算时,其基本操作为 “ 字符序列
的复制 ” 。
1 .串联结
Contcat ( &T,S1,S2 )

        S1 [ 0           S2 [ 0
          ]                ]
S1                 S2


T


                 T[0]             MAXSTRLEN


     S1[0]+S2[0] <= MAXSTRLEN
S1 [ 0           S2 [ 0
              ]                ]
    S1                 S2


                                 S2 中被截去的
    T                               字符序列


               T[0]     MAXSTRLEN



S1[0] < MAXSTRSIZE 而 S1[0]+S2[0] > MAXSTRSIZE
S1 [ 0               S2 [ 0
         ]                    ]
S1                  S2


T
                                S2 串被全部截
                                    去
     T[0]       MAXSTRLEN



     S1[0] = MAXSTRLEN
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
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
定长顺序存储表示的特点与问题
1 . 实现串操作的原操作为“ 字符序列的复制” ,操
作的时间复杂度基于复制的字符序列的长度。
2. 在操作中出现串值序列的长度超过 MaxS trLe n
时,约定用截尾法处理,这种情况可能在联结串
或插入 , 置换时发生。
3. 克服这个问题惟有不限定串长的最大长度,即
动态分配串值的存储空间。
4.2.2 堆分配存储表示
   以一组地址连续的存储单元存储串值的字符序
列,存储空间在程序执行过程中动态分配。
   C 语言中提供的串类型就是以这种存储方式实
现的。系统利用函数 m allo c () 和 fre e ( ) 进行串值空
间的动态管理,为每一个新产生的串分配一个存储
区,称串值共享的存储空间为“ 堆”。
   C 语言中的串以一个空字符为结束符,串长是
一个隐含值。
typedef struct {
   char *ch; // 若是非空串,则按串长分
                          配存储区 , 否则
ch 为 NULL
   int length;   // 串长度
} HString;
这类串操作实现的算法为:
  先为新生成的串分配一个存储空间,然后进行
串值的复制。
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;
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
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
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;
4.2.3 块链存储表示
   以链表存储串值,除头指针外还可
以附设一个尾指针指示链表中的最后一
个结点,并给出当前串的长度。称如此
定义的串存储结构为 块链结构。 结点大小
          块链结构
#define CHUNKSIZE 80 // 可由用户定义的块大小
typedef struct Chunk { // 结点结构
  char ch[CUNKSIZE];
  struct Chunk *next;
 } Chunk;
typedef struct { // 串的链表结构
  Chunk *head, *tail; // 串的头和尾指针
   int curlen; // 串的当前长度
 } LString;
例如 : 在编辑系统中,整个文本编辑区可
以看成是一个串,每一行是一个子串,构
成一个结点。即 : 同一行的串用定长结构
(80 个字符 ), 行和行之间用指针相联接。


       数据元素所占存储位
存储密度 = 实际分配的存储位
存储密度的大小直接影响着串处理的效
  率.
1. 存储密度小 , 运算处理方便 , 但存储占用
  量大 .
2. 存储密度小 , 在串处理过程中需要进行内
  外存交换的话 , 会因为内外存交换操作过
  多而影响处理的总效率 .
   串值的链式存储结构对于某些串操作
有一定方便处 , 但总的说来不如另外两种存
储结构灵活 , 它占用存储量大且操作复杂 .
练习 : 设 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)))

第四章 串

  • 1.
    第四章 串 4.1 串类型的定 义 4.2 串的表示和实现
  • 2.
    学习提要: 1. 熟悉串的基本操作的定义,并能利用这 些 基本操作来实现串的其它各种操作的方法 。 2. 熟练掌握在串的定长顺序存储结构上实 现串的各种操作的方法。 3. 掌握串的堆分配存储结构以及在其上实 现串操作的基本方法。 4. 了解串的块链存储结构。 重难点内容: 串的存储结构
  • 3.
    §4.1 串类型的定义 基本概念 串( string):由零个或多个字 符组成的有限序列,也称字符串。 记为: S = ‘a1a2a3……an’ (n≥0) 如: A= ‘BEIJING’ , B= ‘JING’
  • 4.
    空串:不含任何字符的串,串长度为 0, 用“ ” 或 ‘ ’ 表示。 空格串:仅由一个或多个空格组成的 串, 长度为串中空格字符的 个数。 如: ‘ ’ , C= ‘ BEI JING ’ 子串:由串中任意个连续的字符组成 的
  • 5.
    字符在串中的位置:字符在序列中的 序号。 子串在主串中的位置:以子串的第一 个字符在主串中的位置来表示。 如: A=‘ BEIJING ’ , B= ‘JING ’ , B 在 A 中的位置为 4 。  串相等:当且仅当两个串的值相等。 也就是说,只有两个串的长度相等且各 个对应位置的字符都相等时才相等。
  • 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 。
  • 10.
    StrLength (S) //求串长 初始条件:串 S 存在。 操作结果:返回 S 的元素个数 ,称为串的长度。
  • 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’
  • 17.
    对于串的基本操作集可以有不同的 定义方法,在使用高级程序设计语言中的 串类型时,应以该语言的参考手册为准。 例如:C 语言函数库中提供下列串处理函数: K 的作用是将 s tr2 中前 gets(str) 输入一个串; k 个字符复制到 s rt1 中 puts(str) 输出一个串; 去,取代 s tr1 中最前面 k 个字符。 strcat(str1, str2) 串联接函数; strcpy(str1, str2, k) 串复制函数; strcmp(str1, str2) 串比较函数; strlen(str) 求串长函数;
  • 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 (StringS, 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 之 前
  • 22.
    串的逻辑结构和线性表极为相 似,区别仅在于串的数据对象约束为 字符集。 串的基本操作和线性表有很大差 别。 在线性表的基本操作中,大多以“ 单个元素 ” 作为操作对象; 在串的基本操作中,通常以“ 串的 整体 ” 作为操作对象。
  • 23.
    §4.2 串的表示和实现 4.2.1 串的定长顺序存储表示 4.2.2串的堆分配存储表示 4.2.3 串的块链存储表示
  • 24.
    4.2.1 定长顺序存储表示 用一组地址连续的存储单元存储串 值的字符序列,类似于线性表的顺序存储 结构。所谓定长顺序存储结构,是直接使 用定长的字符数组来定义,数组的上界预 先给出: #define MAXSTRLEN 255 // 用户可在 255 以内定义最大串 长 typedef unsigned char SString[MAXSTRLEN + 1];
  • 25.
    特点 : 串的实际长度可在这个予定义长 度的范围内随意设定,超过予定义 长度的串值则被舍去,称之为“ 截 断”。 按这种串的表示方法实现的串的 运算时,其基本操作为 “ 字符序列 的复制 ” 。
  • 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. 串比较 ; IntStrCompare(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,HstringS,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;
  • 40.
    例如 : 在编辑系统中,整个文本编辑区可 以看成是一个串,每一行是一个子串,构 成一个结点。即: 同一行的串用定长结构 (80 个字符 ), 行和行之间用指针相联接。 数据元素所占存储位 存储密度 = 实际分配的存储位
  • 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)))