4.1 串
基本概念
串:由n个字符组成的有序序列(特殊的线性表)。记作:s=”s0,s1,…s(n-1)”,其中s为串名,n为串的长度,双引号括起来的字符序列为串的值,每个字符s(i)(0<i<n-1)可以是任意的ASCII码字符,一般为字母(需要注意大小写),数字,标点符号等可显字符。
子串:一个串中任意个连续的字符组成的子序列。包含子串的串称为该子串的主串。
与线性表的差别:
(1)线性表的数据元素可以是任意数据类型,串的数据元素只能是字符类型;
(2)线性表一次操作一个数据元素,串一次操作若干个数据元素,即一个子串。
字符在串中的位置:串中每个字符的顺序编号(为大于等于0的整数)
串的抽象数据类型
数据集合:可以表示为字符序列s0,s1,…s(n-1),每个数据元素的类型为字符类型。例如:
S1=”I am a student”,S2=”student”
操作集合:
- 初始化Initiate(S)
- 赋值Assign(S,T) 把串T的值赋给串S
- 求长度Length(S):如:Length(S1)=14
- 比较Compare(S4,S1)
- 插入Insert(S,pos,T): 在串S的第pos个字符前插入串T,如:Insert(S1,4,”not”)操作后,串S1=”I am not a student”
- 删除Delete(S,pos,len):若满足条件0<pos<Length(S)-1,len>=1和pos+len<=Length(S)-1,则删除串S中从第pos个字符开始、长度为len个的子串,如:Delete(S1,6,7)操作后,串S1=”I am a”
- 取子串SubString(S,pos,len)
- 查找子串Search(S1,0,S2)
- 替换子串Replace(S,start,T)
C语言的串函数
4.2 串的存储结构
分类:顺序存储结构和链式存储结构
顺序存储结构又分为静态数组结构和动态数组结构
- 静态数组结构(静态分配内存方法定义数组)
结构体定义如下:
typedef struct
{
char str[MaxSize];
int Length;
}String;
MaxSize表示数组元素的个数,str表示数组名,length表示串的长度,String为结构体名
- 动态数组结构(动态分配内存方法定义数组)
结构体定义如下:
typedef sstruct
{
char *str;
int MaxLength;
int Length;
}DString;
动态数组的数组名和元素个数是分开定义的char *str; int MaxLength;
串的链式存储结构有单字符结点链和块链
- 单字符结点链(空间利用率低)
结构体定义如下:
typedef struct Node
{
char str;
struct Node *next;
}SCharNode;
- 块链
结构体定义如下:
typedef struct Node
{
char str[Number];
struct Node *next;
}NCharNode;
Number为每个结点数据域的字符数。当数值较大时,块链的空间利用率比单字符结点链高很多。当数值较大时,块链的空间利用率和串的顺序存储结构的空间利用率接近。
4.3 串基本操作的实现算法
1、静态数组下串基本操作的实现算法
串的静态数组结构体定义:
typedef struct
{
char str[MaxSize];
int length;
}String;
静态数组下串基本操作:
//初始化
void Initiate(String *S)
{
S->length=0;
}
//插入子串
int Insert(String *S,int pos,String *T) //在串S的pos位置插入子串T
{
int i;
if(pos<0||pos>S->length)
{
printf("pos参数错误!\n");
return 0;
}
else if(S->length+T->length>MaxSize)
{
printf("数组空间不足无法插入!\n");
return 0;
}
else
{
for(i=S->length-1;i>=pos;i--)
S->str[i+T->length]=S->str[i]; //依次后移数据元素
for(i=0;i<T->length;i++)
S->str[pos+i]=T->str[i]; //插入
S->length =S->length+T->length; //产生新的串长度
return 1;
}
}
//删除子串
int Delete(String *S,int pos,int len)
{
int i;
if(S->length<=0)
{
printf("数组中无数据元素可删!\n");
return 0;
}
else if(pos<0||len<0||pos+len>S->length)
{
printf("参数pos和len不合法!\n");
return 0;
}
else
{
for(i=pos+len;i<=S->length;i++)
{
S->str[i-len]=S->str[i]; //依次前移数据元素
S->length =S->length-len; //产生新的串长度值
}
}
}
//取子串
int SubString(String S,int pos,int len,String *T) //取串S中从pos位置开始长度为len的子串赋值给串T
{
int i;
if(pos<0||len<0||pos+len>S->length)
{
printf("参数pos和len不合法!\n");
return 0;
}
else
{
for(i=0;i<len;i++)
T->str[i]=S.str[pos+i]; //给子串T赋值
T->length=len;
return 1; //给子串的长度赋值
}
}
2、动态数组下串的基本操作实现算法
串的动态数组结构体定义:
typedef struct
{
char *str;
int maxLength;
int length;
}DString;
动态数组下串的操作:
//初始化
void Initiate(DString *S,int max,char *string)
{
int i;
S->str=(char *)malloc(sizeof(char)*max); //申请动态数组空间
S->maxLength=max; //置动态数组最大值
S->length=strlen(string); //置串的当前长度值
for(i=0;i<S->length;i++)
S->str[i]=string[i]; //赋串值
}
//插入子串
int Insert(DString *S,int pos,DString T)
{
int i;
char *p;
if(pos<0||pos>S->length)
{
printf("参数pos出错!\n");
return 0;
}
else
{
if(S->length+T.length>S->maxLength)
{
p=(char *)realloc(S->str,(S->length+T.length)*sizeof(char)); //重新申请数组空间,原数组元素存放在新数组的前面
if(p=NULL)
{
printf("内存空间不足!");
return 0;
}
}
for(i=S->length-1;i>=pos;i--)
S->str[i+T.length]=S->str[i]; //依次后移数据元素
for(i=0;i<T.length;i++)
S->str[pos+i]=T.str[i]; //插入
S->length=S->length+T.length; //产生新的串长度值
return 1;
}
}
//删除子串
int Delete(DString *S,int pos,int len)
{
int i;
if(S->length<=0)
{
printf("数组中未存放字符,无元素可删!\n");
return 0;
}
else if(pos<0||len<0||pos+len>S->length)
{
printf("参数pos和len不合法!");
return 0;
}
else
{
for(i=pos+len;i<=S->length-1;i++)
S->str[i-len]=S->str[i];
S->length=S->length-len;
return 1;
}
}
//取子串
int SubString(DString *S,int pos,int len,DString *T)
{
int i;
if(pos<0||len<0||pos+len>S->length)
{
printf("参数pos和len出错!");
return 0;
}
else
{
for(i=0;i<len;i++)
T->str[i]=S->str[pos+i];
T->length=len;
return 1;
}
}
//撤销操作
void Destory(DString *S) //释放动态数组内存空间
{
free(S->str);
S->maxLength=0;
S->length=0;
}
4.4 串的模式匹配算法(查找)
常用顺序结构下串的模式匹配算法:Brute-Force算法和KMP算法
Brute-Force算法(重要)
KMP算法