1.定义:定长顺序串是将串设计成一种静态结构类型,串的存储分配是在编译时完成的。与前面所讲的线性表的顺序存储结构类似,可用一组地址连续的存储单元存储串的字符序列。
#include <stdio.h>
#define MAXLEN 40
typedef struct
{
char ch[ MAXLEN] ;
int len;
} SString;
【问题分析】在进行顺序串的插入时,插入位置 pos 将串分为两部分(假设为 A、 B,长度为LA、 LB)及待插入部分(假设为 C,长度为 LC),则串由插入前的 AB 变为 ACB,由于是顺序串,插入会引起元素的移动。可能出现以下三种情况: ①插入后串长( LA+LC +LB)≤ MAXLEN,则将 B 后移 LC 个元素位置,再将 C 插入。 ②插入后串长>MAXLEN 且 pos+LC≤ MAXLEN,则 B 后移时会有部分字符被舍弃。 ③插入后串长> MAXLEN 且 pos +LC >MAXLEN,则 B 的全部字符被舍弃(不需后移),并 且 C 在插入时也有部分字符被舍弃。 【算法描述】
StrInsert ( SString * s, int pos, SString t)
{
int i;
if ( pos < 0 || pos > s-> len)
return ( 0 ) ;
if ( s-> len + t. len <= MAXLEN)
{
for ( i = s-> len + t. len - 1 ; i >= t. len + pos; i-- )
s-> ch[ i] = s-> ch[ i - t. len] ;
for ( i = 0 ; i < t. len; i++ )
s-> ch[ i + pos] = t. ch[ i] ;
s-> len = s-> len + t. len;
}
else if ( pos + t. len <= MAXLEN)
{
for ( i = MAXLEN - 1 ; i > t. len + pos - 1 ; i-- )
s-> ch[ i] = s-> ch[ i - t. len] ;
for ( i = 0 ; i < t. len; i++ )
s-> ch[ i + pos] = t. ch[ i] ;
s-> len = MAXLEN;
}
else
{
for ( i = 0 ; i < MAXLEN - pos; i++ )
s-> ch[ i + pos] = t. ch[ i] ;
s-> len = MAXLEN;
}
return ( 1 ) ;
}
显然,实现顺序串插入的算法其实现复杂度为: O( s->len+t.len)。
StrDelete ( SString * s, int pos, int l)
{
int i;
if ( pos < 0 || pos > ( s-> len - l) )
return ( 0 ) ;
for ( i = pos + l; i < s-> len; i++ )
s-> ch[ i - l] = s-> ch[ i] ;
s-> len = s-> len - l;
return ( 1 ) ;
}
3. 串的简单模式匹配 Brute-Force(布鲁特-福斯)算法
【算法思想】
简单的模式匹配算法是一种带回溯的匹配算法,算法的基本思想是:从主串S 的第 pos 个字符开始,和模式串 T 的第一个字符开始比较,如果相等,就继续比较后续字符,如果不等,则从(回溯到)主串 S 的第 pos+1 个字符开始重新和模式串 T 比较,直到模式串 T 中的每一个字符和主串 S 中的一个连续字符子序列全部相等,则称匹配成功,返回和 T 中第一个字符相等的字符在主串 S 中的位置;或者主串中没有和模式串相等的字符序列,则称匹配不成功。
【算法描述】
实现时设 i、 j、 start 三个指示器: i——指向主串 S 中当前比较的字符,起始指向 S 的首字符,此后,每比较一步,后移一步,一趟匹配失败时,回溯到该趟比较起点的下一位置。 j———指向子串 T 中当前比较的字符,起始指向 T 的首字符,此后,每比较一步,后移一步,一趟匹配失败时,回溯到 T 的首字符处。 start———记录每趟比较时在主串 S 中的起点,每趟比较后,后移一步,以便确定下一趟的起始位置。
【算法思想】
从主串s的pos位置起,与模式串t逐位匹配 ①初始化:主串从pos开始,模式串从头开始 ②两串逐位比较:当主串模式串均未遍历完时,对应字符作比较 若相等:主串模式串的当前比较位置均后移 若不等:主串从开始比较位置的下一个开始,模式串从头开始 ③判别:若匹配成功返回起始位置,若不成功,返回-1
StrIndex ( SString s, int pos, SString t)
{
int i, j, start;
if ( t. len == 0 )
return ( 0 ) ;
start = pos;
i = start;
j = 0 ;
while ( i < s. len && j < t. len)
if ( s. ch[ i] == t. ch[ j] )
{
i++ ;
j++ ;
}
else
{
start++ ;
i = start;
j = 0 ;
}
if ( j >= t. len)
return ( start) ;
else
return ( - 1 ) ;
}
【算法分析】
该算法思路比较简单,但最坏时间复杂度较高,为 O( s.len* t.len),如主串为 51 个 0 ,模式串为 7 个 0 后有个 1 ,每趟都在最后一个不匹配后而倒到 start+1 ,整个匹配过程 共需 s.len- t.len=45 趟,每趟比较 t.len=8 个字符,故此例整个比较了 360 次。这个算法的主要 时间耗费在失配后的比较位置有回溯,造成了比较次数太多的情况。降低时间复杂度可采用 无回溯的算法——KMP算法
1.字符串包括串名与串值两部分,而串值采用堆串存储方法存储,串名用符号表存储。
堆串存储方法:仍以一组地址连续的存储单元顺序存放串中的字符,但它们的存储空间是在程序执行过程中是动态分配的。系统将一个地址连续、容量很大的存储空间作为字符串的可用空间,每当建立一个新串时,系统就从这个空间中分配一个大小和字符串长度相同的空间存储新串的串值。 串名符号表:所有串名的存储映像构成一个符号表。借助此结构可以在串名和串值之间建立一个对应关系,称为串名的存储映像。
typedef struct
{
char * ch;
int len;
} HString;
StrInsert ( HString * s,int pos,HString * t)
{
int i;
char * temp;
if ( pos < 0 || pos > s-> len || s-> len == 0 )
return ( 0 ) ;
temp = ( char * ) malloc ( s-> len + t-> len) ;
if ( temp == NULL )
return ( 0 ) ;
for ( i = 0 ; i < pos; i++ )
temp[ i] = s-> ch[ i] ;
for ( i = 0 ; i < t-> len; i++ )
temp[ i + pos] = t-> ch[ i] ;
for ( i = pos; i < s-> len; i++ )
temp[ i + t-> len] = s-> ch[ i] ;
s-> len + = t-> len;
free ( s-> ch) ;
s-> ch = temp;
return ( 1 ) ;
}
StrDelete ( HString * s,int pos,int len)
{
int i;
char * temp;
if ( pos < 0 || pos > ( s-> len - len) )
return ( 0 ) ;
temp = ( char * ) malloc ( s-> len - len) ;
if ( temp == NULL )
return ( 0 ) ;
for ( i = 0 ; i < pos; i++ )
temp[ i] = s-> ch[ i] ;
for ( i = pos; i < s-> len - len; i++ )
temp[ i] = s-> ch[ i + len] ;
s-> len = s-> len - len;
free ( s-> ch) ;
s-> ch = temp;
return ( 1 ) ;
}