《第4章串》习题解答docx.docx
《《第4章串》习题解答docx.docx》由会员分享,可在线阅读,更多相关《《第4章串》习题解答docx.docx(37页珍藏版)》请在冰豆网上搜索。
![《第4章串》习题解答docx.docx](https://file1.bdocx.com/fileroot1/2023-2/6/e807a198-1f2c-4d8b-9082-190c33bb72f3/e807a198-1f2c-4d8b-9082-190c33bb72f31.gif)
《第4章串》习题解答docx
本章学习要点
♦熟悉串的相关概念以及串与线性表的关系
♦重点掌握串的定长存储、堆分配存储的表示方法与基本操作的实现
♦了解串的各种存储结构,能根据需要合理选用串的存储结构解决实际问题
“串”(string),是字符串的简称,它是一种特殊的线性表,其特殊性在于组成线性表的数据元素是单个字符,并且在串的各种基本操作中都是以串(或子串)作为操作对象。
字符串在计算机处理实际问题中使用非常广泛,比如人名、地名、商品名、设备名等均为字符串。
同样在文字编辑、自然语言理解和翻译、源程序的编辑和修改等方面,都离不开对字符串的处理。
4.1串的基本概念
4.1.1串的概念
1.串的定义
串(string)是由n个字符组成的有限序列,记为:
S="aoa1a2...an.1"(n>0)o
其中,S是串的名字,字符序列aoa1a2...an.1是串的值,务(0主ml)可以是字母、数字或其他字符元素;由于在C语言系统中数组元素的下标是从0开始的,所以串屮所含元素的序号等于该元素的下标值加1;串屮所含字符的个数n称为该串的长度,长度为0的字符串称为空串(null
string)o
从串的定义可以看出,串实际上是数据元素为字符的特殊的线性表。
(长度为4的串)
(长度为11的串)
(长度为8的串)
(长度为0的空串)(长度为16的串)
(长度为6的串)
例如:
(1)A=“X123"
(2)B=“l2345654321”
(3)C=“BeiJing"
(4)D=“"
(5)E=“Thisisastring^^
(6)F=''isa"
2.子串、主串和位置
串屮任意连续的字符纽•成的子序列称为该串的子串;相应地,包含子串的串称为主串。
串中的字符在串序列中的序号称为该字符在该串中的位置;子串的第一个字符在主串中的位瓷称为子串在主串中的位置。
显然,串为其B身的子串,并规定空串为任何串的子串。
显然,在不考虑空子冷的情况下,一个长度为n的字符串具有n(n+l)/2个子串。
例如:
在上例的(6)中串F就是(5)中串E的子串,且子串F在主串E中的位置是5。
由于空格符也是一•个字符,所以在串G=“abcdefghneT||包含有子串tucdef\而串“cdef,不是串G的子串。
串G中第一个字符®的位置是6,笫二个字符®的位置是Ik
3.串的比较
如來两个串的长度相等且对应位置上的字符相同,则称这两个串相等。
两个串A、B的比
较过程是:
从前往后逐个比较对应位置上的字符的ASCII码值,直到不相等或有一个字符串结束为止,此时的情况有以下几种:
(1)两个串同时结束,表示A等于B;
(2)A中字符的ASCII码值人于B小相应位査上字符的ASCII码值或B串结束,表示A大于B;
(3)B中字符的ASCII码值大于A中相应位置上字符的ASCII码值或A串结束,表示A小于Bo
例如:
“abc''=“abc",“abc''v“abcd",“abxy">“abcdefg‘,T32">T23456",“ABab''v“abAB",“3+2,,>“2+3”。
4.空格串
由一个或多个空格字符组成的串称为空格串,空格串的长度为串中所含空格字符的个数。
在串操作中不要将空格串和空串混淆。
4.1.2串的基本操作
尽管串的定义和线性表极为和似,但是串的基本操作和线性表有很大差別。
在线性表的基木操作屮,人多以单个元素作为操作对象,比如对线性表的查找、访问、插入、删除和排序等;而在串的基本操作中,通常以串整体或串的一部分(子串)作为操作对象,比如子串的查找、截取子串、删除一个子串、插入子串和子串替换等操作。
串的基本操作主要有:
(1)初始化串StrAssign(&T,chars)由字符串常量chars生成字符串T的操作。
(2)串复制StrCopy(&T,S)由串S复制主成串T的操作。
(3)串比较StrCompare(S,T)若S=T返冋0,S>T返回正数,S(4)求串长度StrLength(S)返回串S的长度。
(5)串连接Concat(&T,Sl,S2)将串S1和S2连接起來生成串T的操作。
(6)求子串SubString(&Sub,S,pos,len)以串S中pos位置开始的len个字符生成子串Sub的操作。
(7)串查找Index(S,T,pos)返回子串T在S中pos个字符以后出现的位置。
(8)串替换Replace(&S,T,V)将串S中所有不重叠子串T替换为串V的操作。
(9)串插入Strlnsert(&S,pos,T)在串S中笫pos个字符前插入串T的操作。
(10)删除子串StrDelete(&S,pos,len)删除串S屮笫pos个字符开始的len个字符的操作。
4.2串的存储表示与实现
既然串是线性表的特例,所以线性表的两种存储结构对于串也是适用的。
在应用小具体选用何种存储结构与串的操作有关,比如对串进行插入和删除操作运算时选用链存储结构较好,对串进行查找和求了串运算时选用顺序存储结构较好。
本章主要介绍串的3种存储表示方法:
(1)串的定长顺序存储表示法
(2)串的堆分配存储表示法
(3)串的块链式存储表示法
4.2.1串的定长顺序存储表示
串的定长顺序存储表示是用一组地址连续的存储单元来存储串屮的字符序列。
在串的定长顺序存储表示屮,按照预定义的大小,为每个定长的串变量分配一个固定长度的存储区,所以nJ"以用定长字符数组来表示。
1.定长顺序存储结构
在C++运行环境中,定长顺序结构定义为:
#includeniostream.hn
〃定义审的最大长度为255
//定义定长顺序存储类型SString
#include"stdio.h"
#detmeMAXLEN255typcdcfcharSString[MAXLEN+l];
2.基本操作的C++程序实现
(1)求串长度操作intLcngth_SS(SStringS)
操作返回串s中所含字符的个数,即串的长度;如果S为空串则返回0。
intLengthSS(SStringS)
{inti=0;
whilc(S[i])i++;
return(i);
}
(2)串连接操作intConcat_SS(SString&T,SStringSI,SStringS2)
该操作将冷SI、S2连接生成gT,如果在连接过程中产生了截断(即S1的长度加上S2的长度大于MAXLEN)则返回0,否则返回1。
intConcat_SS(SString&T,SStringSI,SStringS2)
{
intij,k;
i=j=k=0;
while(T[i++]=Sl[j++]);
i・・;
while(iT[i]=0;
if((i==MAXLEN)&&S2[k])rctum(O);/*判断是否产生截断*/
elseretum(l);
}
(3)求子串操作intSubString_SS(SString&Sub,SStringS,intpos,intlen)
该操作截収冷S中从笫pos个字符开始的连续的len个字符生成子串Sub,如果位置pos和长度len合理则返回1,否则返回0.
intSubString_SS(SString&Sub,SStringS,intpos,intlen)
inti=0;
if(posLength_SS(S)4-l)return0;/*判断位置和长度是否合理*/
whilc(iSub[i]=*\0:
return1;
}
(4)初始化串操作intStrAssignSS(SString&T,char*s)
该操作用字符数组s,初始化定长顺序串T。
如果不产生截断(长度合理)返冋1,否则返回0。
intStrAssignSS(SString&T,char*s)
{
inti=0;
while(iT[i]=0;
if((i==MAXLEN)&&s[i])return0;/*判断是否产生截断*/
elsereturn1;
}
(5)串复制操作voidStrCopy_SS(SString&T,SStringS)
该操作将定长顺序串S,复制到定长顺序串To
voidStrCopySS(SString&T,SStringS)
{inti=0;
whilc(T[i]=s[i])i++;
}
(6)串比鮫操作intStrCompare_SS(SStringS,SStringT)
该操作比较顺序串S、T的大小,如果S>T则返回正数,如果S=T则返回0,否则返回负数。
intStrComparc_SS(SStringS,SStringT)
{
inti=0;
while(S[i]&&T[i]&&(S[i]==T[i]))i++;
return(int)(S[i]-T[i]);
}
(7)串的替换操作intReplace_SS(SString&S,intn,intm,SStringT)
该操作将串S中从第n个字符开始的连续的m个字符替换成串T中的字符,如果n和m的选取合理则返回1,否则返回0。
intReplace_SS(SString&S,intn,intm,SStringT)
SStringSI;
intlen=LengthSS(T);
inti=n-lj=O,k=n+m-l;
/*i为开始普换位置,j指向第一个普换字符,k为剩余字符的开始位置
if(nLength_SS(S)+l||Length_SS(S)+len-m>MAXLEN)retum(O);
/客判断位置是否合理可
(8)主函数演示程序main()
voidmain_SS()
{
SStringsl,s2,s3,sub,T;
charstrl[100],str2[100];
int11,12,13,posJen,n;
while(l)
{cout«n(l)串初始化操作:
\n输入两个字符串An”;cin.getline(strl,sizeof(strl));
/*表示从键盘输入一-个可以含冇空格字符的长度小于100的字符串到strl中,语句“cin>>strl”不能输入空格字符(空格符表示输入结束)且对串的长度不做检査。
*/
cin.getline(str2,sizeof(str2));
StrAssignSS(s1,strl);
StrAssign_SS(s2,str2);ll=Lcngth_SS(sl);
!
2=Length_SS(s2);
cout«n
(2)求串长操作:
\nsl的长度=”«ll«n,s2的长度="«12«endl;n=StrCompare_SS(s1,s2);
coutvv”⑶串比较操作:
\n比较结果为:
”;
if(n>0)cout«usl>s2\nn;
elseif(n=0)cout«ns1=s2\nM;
elsecout«nslConcat_SS(s3,s1,s2);
cout«n(4)串连接操作:
\nsl4-s2=H«s3«endl;
13=Lcngth_SS(s3);
cout«ns1+s2的长度=M«13«endl;
cout«”(5)求了串操作:
\n输入开始位置和串长(poslen):
\nn;
cin»pos»len;
if(SubStringSS(sub,s3,pos,len))cout«nsub="«sub«endl;
elsecout«n位置不正确\n”;
cout«”(6)申替换操作:
\n输入替换的位置和字符数(poslen):
n;cin»pos»len;
cout«”输入替换串:
\n";cin.get();
cin.getline(str1,sizeof(str1));
StrAssign_SS(T,str1);if(Replace_SS(s3,pos,Ien,T))cout«H替换结果为:
\ns3=H«s3«endl;elsecout«”替换不成功!
\n";
}
}(程序运行过程略)
3.定长顺序存储的特点
定长顺序存储的串在基木操作方面主要有以下特点:
(1)对于求串长度和串的复制操作而言,其时间复杂度依赖于字符串的长度;
(2)在串删除和串插入操作时必须移动大量的字符;
(3)如呆在串输入、串连接、串插入和串替换操作中串值的长度超过MAXLEN,则按约定釆取“截尾”法处理,这将导致操作结果的不合理。
4.2.2串的堆分配存储表示
由于串操作基木上是以串整体的形式参与,在应用程序中串变量的氏度相差较大,并且在操作中串值长度的变化也比较大。
因此,事先为串变量设置固定大小空间的数组不尽合理。
用堆分配存储表示串的方法是:
在程序执行过程中,根据串变量值的人小,在堆空间中动态分配一个连续的地址空间來存储串变暈屮的字符,这样既可以避免产生串操作屮的“截断”现象又能合理使用内存空间资源。
1.串的堆分配存储结构
在C++运行环境中,堆分配存储结构定义为
structHString
{char*ch;〃串变量屮字符数纽的首地址
intlength;//串的长度
};
2.在堆分配存储结构中串基本操作的C++程序实现
(1)串的赋值操作voidStrAssign_HS(HString&T,charstr[])
该操作山字符串常量str生成一•个HString型串T。
voidStrAssign_HS(HString&T,charstr[])+909・
{intlcn=0,i;
whilc(str[lcn])lcn++;//计算串的长度
(2)求串长的操作intLengthHS(HStringS)
该操作返冋串S的长度,如果S为空串则返冋0。
intLength_HS(HStringS){return(S.length);}
(3)串的比较操作intStrComp_HS(HStringS,HStringT)
该操作比较串S、T的人小。
intStrComp_HS(HStringS,HStringT){inti;
for(i=0;i=T.ch[i])break;
retum((int)(S.ch[i]-T.ch[i]));
(4)串的清空操作voidClearString_HS(HString&S)
该操作清空串S所占的堆空间。
voidClearString_HS(HString&S){if(S.ch)
{delete[]S.ch;
S.ch=NULL;
S.length=0;
(5)串的连接操作voidConcat_HS(HString&T,HStringSl,HStringS2)
该操作计算串SI、S2的连接串T。
voidConcat_HS(HString&T,HStringSl,HStringS2)
{
inti,j,k;
T.length=Sl.length+S2.length;
i=j=k=O;
T.ch=newchar[T.length+l];〃分配链接串的储存空间
while(T.ch[i++]=Sl.chfj+4-]);〃将SI复制到T
}
(6)求子串的算法intSubStringHS(HString&Sub,HStringS,intpos,intlen)
该操作求串Spos个字符开始的len个字符组成的子串Sub,如果位置合理返M1否则返回0。
intSubString_HS(HString&Sub,HStringS,intpos,intlen)
{
inti;
if(pos<11|len<1||pos+len>S.length+1)retum(O);〃如果位置不合理时返回0值
Sub.ch=newchar[len+l];〃动态分配子串的存储空间
Sub.length=len;
for(i=0;iSub.ch[i]=0;
rctum(l);
}
(7)串插入操作的算法intStrInsert_HS(HString&S,intpos,HStringH)
该操作在串S的笫pos个字符前面插入字符串H,如果位置合理返回1,否则返回0ointStrInsert_HS(HString&S,intpos,HStringH)
(8)串替换操作的算法intRcplacc_HS(HString&S,intn,intm,HStringT)
该操作将串S中第n个字符开始的m个字符替换为串T,如果位置n和字符数m合理返回1否则返回0o
intRcplacc_HS(HString&S,intn,intm,HStringT)
inti,j,k=n+m-1;
〃长度或位置不合理
〃重新分配储存空间
〃取S中前面的部分
〃取T中的内容
〃取S小剩余的部分
HStringSI;
if(nS.length+l)return(O);
S1.length=S.length+T.length-m;
S1.ch=newchar[S1.lengths1];for(i=0;ifbr(j=OJdelete[]S.ch;
S=S1;
retum
(1);
}
(9)主函数演示程序main()
voidmain_HS()
{
HStringS1,S2,S,sub,V,T;
SStringssl,ss2;
intn,pos,len;
whilc(l)
{
cout«”(l)串初始化操作:
\n输入两个字符串:
\n”;
cin.getline(ss1,sizeof{ss1));
cin.getline(ss2,sizeof{ss2));
StrAssign_HS(S1,ss1);
StrAssign_HS(S2,ss2);
cout«n
(2)求串长操作:
\nlen1=,'«LengthHS(Sl)«endl;cout«Hlen2=,,«Length_HS(S2)«endl;
coutvv”⑶串比较操作:
\n比较大小的结果为:
”;n=StrComp_HS(S1,S2);
if(n>0)cout«,,Sl>S2\nH;
elseif(n<0)cout«nSlelsecoutConcat_HS(S,Sl,S2);
cout«n(4)串连接操作:
\n:
s1+s2=H«S.ch«endl;cout«Hlcngth=n«Lcngth_HS(S)«cndl;
cout«”(5)取了串操作:
\n输入取了串的位置和长度(poslen):
\nM;cin»pos»len;
if(SubString_HS(sub,S,pos,len))cout<elsecout«n位置不对!
\n”;
cout\n请输入插入位置:
";cin»pos;cin.get();cout«n输入要插入的子串V:
\n”;cin.getline(ssl,sizeof(ss1));
StrAssign_HS(V,ss1);ifi(StrInsert_HS(S,pos,V))cout«n插入结果为s=u«S.ch«endl;elsecout«*'位置不对!
\n”;
coutv<”(7)申替换操作;\n输入替换子串的位置和长度(poslen):
\nu;cin»pos»len;cin.get();
cout«n输入替换串T:
\n";cin.getline(ss1,sizeof(ss1));
StrAssign_HS(T,ss1);if(Rcplacc_HS(S,pos,lcn,T))cout«'*结果为s=n«S.ch«cndl;elsecout«n位置不对!
\n”;
3.堆分配存储表示的特点
从以上串基本操作的算法可以看出,堆分配存储结构的串既有顺序存储结构的特点,处理方便,同时在操作屮对串的长度又没有任何限制,更显灵活,因此该存储结构在有关字符串处理的应用程序中常被采用。
4.2.3串的块链式存储表示
1.块链式存储的概念
和线性表的链式存储结构类似,可以采用链表方式存储串。
由于串中的每个数据元索是一个字符,在用链表存储串值时,存在一个“结点大小”的问题,即每个结点最多可以存放多少个串中字符。
対于串“abedefghijk”,如果采用每个结点存放一个字符的链表结构存储,其存储方式如图4.1(a)所示;如果采川每个结点存放三个字符的链表结构存储,其存储方式如图4.1(b)所示。
由于串长不一定是结点大小的整数倍,所以在链表的最后一个结点不一定能被串中的字符占满,此时可补上若干个非串值字符(或其它非串值字符)。
he画
结点大小为1个字符的链表
he詞一►—不卜》罔卜》剧卜》两]
(b)结点大小为3个字符的琏表
图4.1串的块链式存储结构
为了便于进行串的操作,当以链表存储串值时,除了头指针head外还可以附设一个指向尾结点的指针tail,并给岀当前串的长度。
称如此定义的串的存储结构为串的块链式存储结构。
2.块链式存储结构的表示
在C卄运行环境中,可将块链式存储结构表示如下:
#dcfincCHUNKSIZE80〃定义每个结点的大小
structChunk
};
structLString{
Chunk*head,*tail;//串的头指针和尾指针
intcurlcn;〃串的长度
};〃块链式结构的类型定义
在一般情况下,对串的操作只需耍从前向后扫描即可,故对串值不必建立双向链表。
设尾指针的目的是为了便于进行串的连接操作,在串连接吋需要处理第一个串尾结点中的无效字符。
3.块链式存储的存储密度
在串的块链式存储结构屮,结点人小的选择很重要,它肓接影响到串处理操作的效率。
如果块选取的充分大时(可在一个块中存储串的所有字符)即为定长存储;如果每个块只放一个字符时即为链表存储。
为了便于研究串值的存储效率我们给出如下存储密度的计算公式:
吊值的存储密度=
串值所占的存储位实际分配的存储位
假定next指针变量占用4个字节,每个字符占用1个字节,每个块中存放m个字符,那