字符串、简称串,它也是一种重要的线性结构。计算机中处理的大部分数据都是字符串数据,例如,学生学籍信息系统的姓名、性别、家庭住址、院系名称等信息都属于字符串数据。串广泛应用于各种专业的信息管理、信息检索、问答系统、机器翻译等系统处理中。
【定义】
串(string)是由零个或多个字符组成的有限序列,一般记作:
S="a1a2a3...an"。
其中,S是串名,用双引号括起来的字符序列是串的值,ai(1≤i≤n)可以是字母、数字或其他字符,n是串的长度。当n=0时,S为空串(null string)。
串中任意一个连续的字符组成的子序列称为该字符的子串。相应的包含子串的串称为主串。通常将字符在串中的序号称为该字符在串中的位置。子串在主串中的位置以子串的第一个字符在主串中的位置来表示。
例如:a、b、c、d是4个串:
a="a professor of Northwest University"
b="Northwest University"
c="Northwest"
d="professor"
它们的长度分别为35、20、9、10,b、c和d都是a的子串,c又是b的子串。b、c和d在a中位置分别是16,16,3,c在b中的位置是1。
两个串是相等的,只有当两个串长度相等,且串中各个对应位置的字符均相等,两个串才相等。例如,上面的a,b,c,d两辆都不相等。
值的注意的是,考虑到与C语言表示方法统一,本文的串都是用双引号括起来的,但是,双引号并不属于串本身的内容,双引号的作用仅仅是为了与整型浮点型数据区分开。
【分类】
串也有两种存储方式:顺序存储和链式存储。最为常用的是串的顺序存储表示,操作起来更为方便。
【顺序串】
采用顺序存储结构的串称为顺序串,又称为定长顺序串。一般采用字符型数组存放顺序串。在串的顺序存储结构中,确定串的长度有两种方法:一种是在串的末尾加上一个结束标记,在C语言中,定义一个串时,系统会自动在串的末尾添加‘\0’作为结束标记。例如,定义一个字符数组:
char str="Northwest University";
则串"Northwest University"在内存中的存放形式如图所示。
其中数组名str指向串的起始地址,“\0”表示串的结束。因此串"Northwest University"的长度为20,不包括结束标记“\0”。但是串长度还需要调用函数strlen或者统计字符个数得到。
另一种方法是增加一个变量length,用它来存放串的长度。例如,用length表示串"Northwest University"长度的方法如图所示。
【存储结构】
//存储结构
typedef struct
{
char str[MAXSIZE];
int Length;
}SeqString;
【串的赋值】
//串的赋值
void StrAssign(SeqString *S, char cstr[])
{
int i=0;
for (i = 0; cstr[i] != '\0';i++)
{
S->str[i] = cstr[i];
}
S->Length = i;
}
【判断串是否为空】
//判断串是否为空
int StrEmpty(SeqString S)
{
if (S.Length==0)
{
return 1;
}
else
{
return 0;
}
}
【求串的长度】
//求串的长度
int StrLength(SeqString S)
{
return S.Length;
}
【串的复制】
//串的复制
void StrCopy(SeqString *T, SeqString S)
{
int i;
for (i = 0; i < S.Length;i++)
{
T->str[i] = S.str[i];
}
T->Length = S.Length;
}
【比较两个串的大小】
//比较两个串的大小
int StrCompare(SeqString S, SeqString T)
{
int i;
for (i = 0; i < S.Length&&T.Length;i++)
{
if (S.str[i]!=T.str[i])
{
return (S.str[i] - T.str[i]);
}
}
return (S.Length - T.Length);
}
【插入串】
在串的第pos位置插入串T。若插入成功,返回1;否则返回0.
串的插入操作具体实现分为3种情况:
第1种情况,在S中插入T后串长不超过能容纳的最长字符,即S->Length+T.Length<=MaxLen
则先将串S中pos后的字符向后移动Len个位置,然后将串T插入S中即可;
第2种情况,若将T插入S后,串长超过能容纳的最长字符但T能完全插入S中,即S->Length+T.Length>MaxLen
则将串S中pos后的字符往后移动Len个位置后,S中的部分字符被舍弃;
第3种情况,将T插入S中,有S->Length+T.Length>MaxLen且T不能完全被插入S中
则T中部分字符和S中第Len位置以后的字符均被舍弃。
/*在串的第pos位置插入串T。若插入成功,返回1;否则返回0.*/
/*串的插入操作具体实现分为3种情况:
第1种情况,在S中插入T后串长不超过能容纳的最长字符,即S->Length+T.Length<=MaxLen
则先将串S中pos后的字符向后移动Len个位置,然后将串T插入S中即可;
第2种情况,若将T插入S后,串长超过能容纳的最长字符但T能完全插入S中,即S->Length+T.Length>MaxLen
则将串S中pos后的字符往后移动Len个位置后,S中的部分字符被舍弃;
第3种情况,将T插入S中,有S->Length+T.Length>MaxLen且T不能完全被插入S中
则T中部分字符和S中第Len位置以后的字符均被舍弃。*/
int StrInsert(SeqString *S, int pos, SeqString T)
{
int i;
if (pos < 0||pos-1>S->Length)
{
cout << "插入位置不正确!";
return 0;
}
if (S->Length + T.Length <=MaxLen)
{
for (i = S->Length + T.Length - 1; i >= pos + T.Length - 1;i--)
{
S->str[i] = S->str[i - T.Length];
}
for (i = 0; i < T.Length;i++)
{
S->str[pos + i - 1] = T.str[i];
}
S->Length = S->Length + T.Length;
return 1;
}
else if (pos+T.Length<=MaxLen)
{
for (i = MaxLen - 1; i > T.Length + pos - 1;i--)
{
S->str[i] = S->str[i - T.Length];
}
for (i = 0; i < T.Length;i++)
{
S->str[i + pos - 1] = T.str[i];
}
S->Length = MaxLen;
return 0;
}
else
{
for (i = 0; i < MaxLen - pos;i++)
{
S->str[i + pos - 1] = T.str[i];
}
S->Length = MaxLen;
return 0;
}
}
【删除串S中pos开始的len个字符】
/*删除串S中pos开始的len个字符*/
int StrDelete(SeqString *S, int pos, int len)
{
int i;
if (pos<0||len<0||pos+len-1>S->Length)
{
cout << "删除位置不合法,参数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;
}
}
【连接串】
将串S连接在串T的末尾。串的连接操作可以分为两种情况: 【清空串操作】
第1种,连接后串长T->Length+S.Length≤MaxLen,则直接将串S连接在串T的尾部;
第2种,连接后串长T->Length+S.Length≥MaxLen且串的长度/*将串S连接在串T的末尾。串的连接操作可以分为两种情况:
第1种,连接后串长T->Length+S.Length≤MaxLen,则直接将串S连接在串T的尾部;
第2种,连接后串长T->Length+S.Length≥MaxLen且串的长度
/*清空串操作*/
void StrClear(SeqString *S)
{
S->Length = 0;
}