数据结构C语言版第四章 串
- 格式:doc
- 大小:42.50 KB
- 文档页数:4
第4章串串:限定数据元素类型的线性表。
1 逻辑结构1.1 定义位串:数据元素属于{0,1}ASCII码串: 数据元素属于ASCII码字符集。
数字串:数据元素属于整数集合2 顺序串///////////////////////////////// // 项目路径:7动态顺序串/////////////////////////////////2.2 构造/析构(测试函数Test1)template <class T>String<T>:: String( ){ m_Data=NULL; m_Size=m_Length=0; }template <class T>String<T>::String(T a[], int n){ m_Size = m_Length = n;m_Data = new T[m_Size];if(!m_Data) throw "内存不够,上溢";for(int i=0; i<m_Length; i++)m_Data[i]=a[i];}template <class T>String<T>::String(String &s) // 拷贝构造函数{ m_Size = m_Length = s.m_Length;m_Data = new T[m_Size];if(!m_Data) throw "内存不够,上溢";for(int i=0; i<m_Length; i++)m_Data[i]=s.m_Data[i];}template <class T>String<T>:: ~String( ){ delete []m_Data; }2.3 比较(测试函数Test2)// 重载<template <class T>bool String<T>::operator<(String &s){ for(int i=0; i<m_Length && i<s.m_Length; i++) { if(m_Data[i]<s.m_Data[i]) return true;if(m_Data[i]>s.m_Data[i]) return false;}if(m_Length<s.m_Length) return true;return false;}// 重载==template <class T>bool String<T>::operator==(String &s){ for(int i=0; i<m_Length && i<s.m_Length; i++) if(m_Data[i]!=s.m_Data[i]) return false; if(m_Length==s.m_Length) return true;return false;}2.4 取子串、连接(测试函数Test3)// 取子串template <class T>String<T> String<T>::Substr(int pos,int len) { if(pos+len>m_Length) // 预防子串长度越界len=m_Length-pos;String<T> s;s.m_Length=s.m_Size=len;s.m_Data = new T[s.m_Size];if(!s.m_Data) throw "内存不够,上溢";for(int i=0; i<len; i++)s.m_Data[i]=m_Data[pos+i];return s;}// 连接stemplate <class T>void String<T>::Concat(String s){ if(m_Length+s.m_Length > m_Size) // 空间不够ReNew(m_Length+s.m_Length);for(int i=0; i<s.m_Length; i++)m_Data[m_Length+i] = s.m_Data[i];m_Length += s.m_Length;}// 重新分配串的存储空间template <class T>void String<T>::ReNew(int size){ T *p=new T[size]; // 重新申请空间 m_Size=size;for(int i=0; i<m_Length; i++) // 数据迁移p[i]=m_Data[i];delete []m_Data; // 释放原串空间 m_Data = p;}2.5 插入、删除(测试函数Test4)// 第i个位置上插入stemplate <class T>void String<T>::Insert(int pos, String s){ if(m_Length+s.m_Length > m_Size) // 空间不够 ReNew(m_Length+s.m_Length);for(int i=m_Length-1; i>=pos; i--) // 向后移位 m_Data[i+s.m_Length] = m_Data[i];for(i=0; i<s.m_Length; i++)m_Data[pos+i] = s.m_Data[i];m_Length += s.m_Length;}// 删除子串template <class T>void String<T>::Delete(int pos,int len){ for(int i=pos+len; i<m_Length; i++) // 向前移位 m_Data[i-len] = m_Data[i];m_Length -= len;}2.6 顺序串的评价优点:访问子串方便,缺点:空间大小不灵活,插入、删除费时。
第四章串重点难点理解"串"类型定义中各基本操作的特点,并能正确利用它们进行串的其它操作;掌握串类型的各种存储表示方法;理解串的两种匹配算法。
典型例题1、简述下列每对术语的区别:空串和空白串;串常量和串变量;主串和子串;静态分配的顺序串和动态分配的顺序串;【解】(1)空串是指不包含任何字符的串,它的长度为零。
空白串是指包含一个或多个空格的串,空格也是字符。
(2)串常量是指在程序中只可引用但不可改变其值的串。
串变量是可以在运行中改变其值的。
(3)主串和子串是相对的,一个串中任意个连续字符组成的串就是这个串的子串,而包含子串的串就称为主串。
(4)静态分配的顺序串是指串的存储空间是确定的,即串值空间的大小是静态的,在编译时刻就被确定。
动态分配的顺序串是在编译时不分配串值空间,在运行过程中用malloc和free等函数根据需要动态地分配和释放字符数组的空间(这个空间长度由分配时确定,也是顺序存储空间)。
2、以HString为存储表示,写一个求子串的算法。
【解】HString 是指以动态分配顺序串为存储表示,其定义为:typedef struct {char *ch;int length;}HString;void *substr( HString *sub,HString *s,int pos,int len){//用sub返回串s的第pos个字符起长度为len的子串。
sub初始时为一空串//pos的合法位置为0<=pos<=s->length-1int i;if (pos<0||pos>s->length-1||len<=0)Error("parameter error!");//参数不合法,子串为空串if (s->length<pos+len)//s串中没有足够的元素sub->len=s->length-pos;//设置子串的串长else sub->length=len; //设置子串的串长sub->ch=(char *)malloc(len*sizeof(char));//为sub->ch申请结点空间for(i=0;i<sub->length;i++)//将s串中pos位置开始的共sub->length个字符复制到sub串中sub->ch[i]=s->ch[pos+i];}3、若S和T是用结点大小为1的单链表存储的两个串,试设计一个算法找出S中第一个不在T中出现的字符。
第四章串
重点难点
理解"串"类型定义中各基本操作的特点,并能正确利用它们进行串的其它操作;掌握串类型的各种存储表示方法;理解串的两种匹配算法。
典型例题
1、简述下列每对术语的区别:
空串和空白串;串常量和串变量;主串和子串;静态分配的顺序串和动态分配的顺序串;【解】
(1)空串是指不包含任何字符的串,它的长度为零。
空白串是指包含一个或多个空格的串,空格也是字符。
(2)串常量是指在程序中只可引用但不可改变其值的串。
串变量是可以在运行中改变其值的。
(3)主串和子串是相对的,一个串中任意个连续字符组成的串就是这个串的子串,而包含子串的串就称为主串。
(4)静态分配的顺序串是指串的存储空间是确定的,即串值空间的大小是静态的,在编译时刻就被确定。
动态分配的顺序串是在编译时不分配串值空间,在运行过程中用malloc和free等函数根据需要动态地分配和释放字符数组的空间(这个空间长度由分配时确定,也是顺序存储空间)。
2、以HString为存储表示,写一个求子串的算法。
【解】HString 是指以动态分配顺序串为存储表示,其定义为:
typedef struct {
char *ch;
int length;
}HString;
void *substr( HString *sub,HString *s,int pos,int len)
{//用sub返回串s的第pos个字符起长度为len的子串。
sub初始时为一空串
//pos的合法位置为0<=pos<=s->length-1
int i;
if (pos<0||pos>s->length-1||len<=0)
Error("parameter error!");//参数不合法,子串为空串
if (s->length<pos+len)//s串中没有足够的元素
sub->len=s->length-pos;//设置子串的串长
else sub->length=len; //设置子串的串长
sub->ch=(char *)malloc(len*sizeof(char));//为sub->ch申请结点空间
for(i=0;i<sub->length;i++)//将s串中pos位置开始的共sub->length个字符复制到sub串中
sub->ch[i]=s->ch[pos+i];
}
3、若S和T是用结点大小为1的单链表存储的两个串,试设计一个算法找出S中第一个不在T中出现的字符。
【解】
查找过程是这样的,取S中的一个字符(结点),然后和T中所有的字符一一比较,直到比完仍没有相同的字符时,查找过程结束,否则再取S中下一个字符,重新进行上述过程。
算法如下:
链串的结构类型定义:
typedef struct node{
char data;
struct node *next;
}LinkStrNode; //结点类型
typedef LinkStrNode *LinkString; //LinkString为链串类型
LinkString S; //S是链串的头指针
char SearchNoin( LinkString S, LinkString T)
{//查找不在T中出现的字符
LinkStrNode *p,*q;
p=S;
q=T;
while (p)
{ //取S中结点字符
while(q&&p->data!=q->data)//进行字符比较
q=q->next;
if(q==NULL) return p->data;//找到并返回字符值
q=T; //指针恢复串T的开始结点
p=p->next;
}
printf("there's no such character.");
return NULL;}
习题精选
一、.单项选择题
1.串是一种特殊的线性表,其特殊性体现在()。
A.可以顺序存储B.数据元素是一个字符
C.可以链式存储D.数据元素可以是多个字符若
2.串下面关于串的的叙述中,()是不正确的?
A.串是字符的有限序列B.空串是由空格构成的串
C.模式匹配是串的一种重要运算D.串既可以采用顺序存储,也可以采用链式存
3.串的长度是指()。
A.串中所含不同字母的个数 B.串中所含字符的个数
C.串中所含不同字符的个数 D.串中所含非空格字符的个数
4.设串s1=’ABCDEFG’,s2=’PQRST’,函数con(x,y)返回x和y串的连接串,subs(s, i, j)返回串s的从序号i开始的j个字符组成的子串,len(s)返回串s的长度,则con(subs(s1, 2, len(s2)), subs(s1, len(s2), 2))的结果串是:
A.BCDEF B.BCDEFG C.BCPQRST D.BCDEFEF
二、算法设计
1.编写算法,实现下面函数的功能。
函数void insert(char*s,char*t,int pos)将字符串t插入到字符串s中,插入位置为pos。
假设分配给字符串s的空间足够让字符串t插入。
(说明:不得使用任何库函数)
[题目分析]本题是字符串的插入问题,要求在字符串s的pos位置,插入字符串t。
首先应查找字符串s的pos位置,将第pos个字符到字符串s尾的子串向后移动字符串t的长度,然后将字符串t复制到字符串s的第pos位置后。
对插入位置pos要验证其合法性,小于1或大于串s的长度均为非法,因题目假设给字符串s的空间足够大,故对插入不必判溢出。
void insert(char *s,char *t,int pos)
//将字符串t插入字符串s的第pos个位置。
{int i=1,x=0; char *p=s,*q=t; //p,q分别为字符串s和t的工作指针
if(pos<1) {printf(“pos参数位置非法\n”);exit(0);}
while(*p!=’\0’&&i<pos) {p++;i++;} //查pos位置
//若pos小于串s长度,则查到pos位置时,i=pos。
if(*p == '/0') {printf("%d位置大于字符串s的长度",pos);exit(0);}
else //查找字符串的尾
while(*p!= '/0') {p++; i++;} //查到尾时,i为字符‘\0’的下标,p也指向‘\0’。
while(*q!= '\0') {q++; x++; } //查找字符串t的长度x,循环结束时q指向'\0'。
for(j=i;j>=pos ;j--){*(p+x)=*p; p--;}//串s的pos后的子串右移,空出串t的位置。
q--; //指针q回退到串t的最后一个字符
for(j=1;j<=x;j++) *p--=*q--; //将t串插入到s的pos位置上
[算法讨论] 串s的结束标记('\0')也后移了,而串t的结尾标记不应插入到s中。
2.写一个递归算法来实现字符串逆序存储,要求不另设串存储空间。
[题目分析]实现字符串的逆置并不难,但本题“要求不另设串存储空间”来实现字符串逆序存储,即第一个输入的字符最后存储,最后输入的字符先存储,使用递归可容易做到。
void InvertStore(char A[])
//字符串逆序存储的递归算法。
{ char ch;
static int i = 0;//需要使用静态变量
scanf ("%c",&ch);
if (ch!= '.') //规定'.'是字符串输入结束标志
{InvertStore(A);
A[i++] = ch;//字符串逆序存储
}
A[i] = '\0'; //字符串结尾标记
}//结束算法InvertStore。
3.写一个算法统计在输入字符串中各个不同字符出现的频度并将结果存入文件(字符串中的合法字符为A-Z这26个字母和0-9这10个数字)。
void Count()
//统计输入字符串中数字字符和字母字符的个数。
{int i,num[36];
char ch;
for(i=0;i<36;i++)num[i]=0;// 初始化
while((ch=getchar())!=‘#’) //‘#’表示输入字符串结束。
if(‘0’<=ch<=‘9’){i=ch-48;num[i]++;} // 数字字符
else if(‘A’<=ch<=‘Z’){i=ch-65+10;num[i]++;}// 字母字符
for(i=0;i<10;i++) // 输出数字字符的个数
printf(“数字%d的个数=%d\n”,i,num[i]);
for(i=10;i<36;i++)// 求出字母字符的个数
printf(“字母字符%c的个数=%d\n”,i+55,num[i]);
}// 算法结束。