数据结构–定长顺序串的c语言实现(超详细注释/实验报告)
知识小回顾
计算机处理的对象分为数值数据和非数值数据,字符串事最基本的非数值数据。字符串处理在语言编译、信息检索、文字编辑等问题中有着广泛的应用。字符串事一种特定的线性表,其特殊性在于组成线性表的每个元素就是一个单字符。
一些定义
字符串:由零个或多个字符组成的有限序列。
子串:串中任意个连续的字符组成的子序列。
字串在主串中的位置:通常是字符在串中的序号称为该字符在串中的位置。字串在主串中的位置则以字串的第一个字符在主串中的位置来表示。
串也是一种特定的线性表,串的逻辑结构和线性表极为相似,其特定性仅在于串的数据对象限定为字符集。
定长顺序串
定长顺序串是将串设计成一种静态结构类型,串的存储分配是在编译时完成的。与之前的线性表的存储结构类似,可以用一组地址连续的存储单元来存储串的字符序列。
实验题目
熟悉串的基本操作:
- 求串长
- 插入运算
- 子串删除
- 串连接
- 取子串
实验目的
- 熟悉串的基本操作
实验要求
- 以顺序串作为存储结构;
- 实现顺序串求串长操作;
- 实现顺序串插入运算操作;
- 实现顺序串子串删除操作;
- 实现顺序串连接操作;
- 实现顺序串取子串操作;
实验内容和实验步骤
1.需求分析
以菜单的形式作为用户与程序的接口,用户输入菜单号来实行相应的操作。
2. 概要设计
设计几个函数来实现初始化、插入、删除和查找的功能,然后再主函数中调用函数来实现操作。
3. 详细设计
导入一些库,并定义顺序串的大小以及顺序串中元素的类型。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<malloc.h>
#define MAXSIZE 255
using namespace std;
typedef char strs[MAXSIZE];
typedef struct
{
strs str;
int length;
}SeqString;
顺序串插入操作
- 在串s中第pos的字符之前插入串t
在这一部分中,我相比于实验指导,增加了其他几个条件分支,使得程序的鲁棒性更加好。
void StrInsert(SeqString s,int pos,SeqString t)
{
//printf("insert函数调用开始\n");
// printf("%d",s.length);
// printf("%d",t.length);
int i;
pos-=1;
if(pos<0||pos>=s.length)//插入的位置不能小于0也不能大于最大长度
{
printf("插入位置不合法\n");
}
if(s.length+t.length<=MAXSIZE)//原串加新串的长度小于最大长度
{
for(i=s.length+t.length-1;i>=t.length+pos;i--)//目的:把原串的pos之后的部分往后移新串的长度位,初始条件:i=最后一个元素;结束条件:i>=字串长度加要插入的位置
{
s.str[i]=s.str[i-t.length];
}
for(i=0;i<t.length;i++)//目的:把新串插进去,新串有多长就循环几次(插入几次)
{
s.str[i+pos]=t.str[i];//从pos开始插,这里要注意数组索引和人类感知的差异
}
s.length=s.length+t.length;//更新串长
}
else if(pos+t.length<=MAXSIZE)//插入后后串长>最大长度,不过串t可以全部插入
{
// printf("2调用\n");
for(i=MAXSIZE-1;i>=t.length+pos;i--)//和上面唯一不同的就是初始条件变了,上面是从插入后的最后一个位置开始的,所以既然插入后已经到达最大长度了,那么就直接用最大长度当初始条件就行了
{
s.str[i]=s.str[i-t.length];//还是一样的
}
for(i=0;i<t.length;i++)//这个和上面是一样的
{
s.str[i+pos]=t.str[i];
}
s.length=MAXSIZE;//更新长度,这时候就方便一些了
}
else//插入后后串长>最大长度,不过串t不可以全部插入
{
// printf("3调用\n");
for(i=0;i<MAXSIZE-pos;i++)//这时候就不用原来串中元素往后移了,最大长度和pos之间有多长,循环就有几次
{
s.str[i+pos]=t.str[i];
}
s.length=MAXSIZE;//更新长度,这时候就和上面一样方便了
}
printf("插入后的串长为:%d\n",s.length);
printf("插入后的串是:");
printf("%s\n",s.str);
}
求串长
//求串长操作
int StrLength(SeqString s)
{
int i=0;
while(s.str[i]!=0)//元素不为零就加一,一直加到元素为零为止
{
i++;
}
s.length=i;
printf("串s的长度为%d\n",s.length);
return s.length;
}
串连接
int StrConcat(SeqString *s,SeqString t)
{
int i;
s->length=strlen(s->str);
t.length=strlen(t.str);
if(s->length+t.length>MAXSIZE)
{
printf("连接后的串长超过最大长度\n");
return 0;
}
else
{
for(i=s->length;i<s->length+t.length;i++)
{
s->str[i]=t.str[i-s->length];
}
}
s->length+=t.length;
printf("两串连接后的长度为%d\n",s->length);
printf("连接后的串是:%s\n",s->str);
return 1 ;
}
串删除
//顺序串的删除操作
void StrDelete(SeqString *s,int pos,int len)
{
int i;
if(pos>s->length||pos+len-1>s->length)
{
printf("删除位置不正确或要删除的字符数量太多了\n");
}
else if(pos<0||len<0)
{
printf("参数输入有误\n");
}
else
{
/*for(i=pos-1;i<pos+len-1;i++)
{
s->str[i]=s->str[i+len];
}算法设计有问题*/
for(i=pos+len-1;i<s->length;i++)
{
s->str[i-len]=s->str[i];
}
s->length=s->length-len;
s->str[s->length]='\0';
printf("删除后的串是:");
printf("%s\n",s->str);
}
}
取子串
- 和串删除有异曲同工之妙
//取子串操作
SeqString *SubString(SeqString s,int pos,int len)
{
int i;
SeqString *r;//新开一个r来存储取出的字串
if(s.length<=0)
{
printf("无子串可取!!\n");
return NULL;
}
else
{
r=(SeqString *)malloc(sizeof(SeqString));//这个地方最后调试的时候改一下
for(i=pos-1;i<pos+len-1;i++)
{
r->str[i-pos+1]=s.str[i];
r->length=len;
r->str[r->length]='\0';
}
}
printf("取出的子串是:");
printf("%s\n",r->str);
return r;
}
主函数部分,用一种“菜单”的形式使线性表的操作更加地清晰地展示出来。
int main()
{
SeqString x,y;
char a[MAXSIZE],b[MAXSIZE];
int a_len,b_len,pos,len,i=1;
while(i)//保证一直进行
{
printf("-------------------------------------\n");
printf(" Main Menu \n");
printf(" 1 求串长 \n");
printf(" 2 插入一个串 \n");
printf(" 3 连接一个串 \n");
printf(" 4 删除子串 \n");
printf(" 5 取子串 \n");
printf(" 6 清屏 \n");
printf(" 0 结束程序 \n");
printf("--------------------------------------\n");
printf("请输入你选择的菜单号<1, 2, 3, 4, 5, 6, 0>:\n");
scanf("%d",&i);
switch(i)
{
case 1:
printf("请输入串:");
scanf("%s",a);
strcpy(x.str,a);
x.length=StrLength(x);
//printf("%d",x.length);
break;
case 2:
printf("请输入原来的串:");
scanf("%s",a);
strcpy(x.str,a);
x.length=StrLength(x);
printf("%d",x.length);
printf("请输入要插入的新串:");
scanf("%s",b);
strcpy(y.str,b);
y.length=StrLength(y);
printf("%d",y.length);
printf("请输入要插入的位置:");
scanf("%d",&pos);
StrInsert(x,pos,y);
break;
case 3:
printf("请输入前串:");
scanf("%s",a);
strcpy(x.str,a);
//StrLength(x);
x.length=StrLength(x);
printf("请输入后串:");
scanf("%s",b);
strcpy(y.str,b);
y.length=StrLength(y);
StrConcat(&x,y);
break;
case 4:
printf("请输入串:");
scanf("%s",a);
strcpy(x.str,a);
x.length=StrLength(x);
printf("从什么地方开始删除?\n");
scanf("%d",&pos);
printf("要删除多长的子串?\n");
scanf("%d",&len);
StrDelete(&x,pos,len);
break;
case 5:
printf("请输入串:");
scanf("%s",a);
strcpy(x.str,a);
x.length=StrLength(x);
printf("从什么地方开始取子串?\n");
scanf("%d",&pos);
printf("要取出多长的子串?\n");
scanf("%d",&len);
SubString(x,pos,len);
break;
case 6:
system("cls");
break;
case 0:
exit(0);
break;
default:
printf("输入有误~");
}
}
return 0;
}
4. 调试分析
遇到的问题及解决方法
- 一开始插入操作一直有问题,每一次都是按最后一个else来执行的,之后试了一些数据,并仔细检查后发现,串的length没有值,所以后来个所有串都加了一个串.length=StrLength(串)。
算法的时空分析
- 顺序串比较简单,都是依托着数组来实现的,所以整体难度不大,最多也就一层循环
实验结果
实验结果很不错,所有操作都能正常执行,还使串插入更加的健壮,并且自己加入了“清屏”选项,使得界面更加的整洁。
实验总结
顺序串需要注意的细节很多,多多重复,百炼成钢!
最后附上完整的代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<malloc.h>
#define MAXSIZE 255
using namespace std;
typedef char strs[MAXSIZE];
typedef struct
{
strs str;
int length;
}SeqString;
//顺序串插入操作
//在串s中第pos的字符之前插入串t
void StrInsert(SeqString s,int pos,SeqString t)
{
//printf("insert函数调用开始\n");
// printf("%d",s.length);
// printf("%d",t.length);
int i;
pos-=1;
if(pos<0||pos>=s.length)//插入的位置不能小于0也不能大于最大长度
{
printf("插入位置不合法\n");
}
if(s.length+t.length<=MAXSIZE)//原串加新串的长度小于最大长度
{
for(i=s.length+t.length-1;i>=t.length+pos;i--)//目的:把原串的pos之后的部分往后移新串的长度位,初始条件:i=最后一个元素;结束条件:i>=字串长度加要插入的位置
{
s.str[i]=s.str[i-t.length];
}
for(i=0;i<t.length;i++)//目的:把新串插进去,新串有多长就循环几次(插入几次)
{
s.str[i+pos]=t.str[i];//从pos开始插,这里要注意数组索引和人类感知的差异
}
s.length=s.length+t.length;//更新串长
}
else if(pos+t.length<=MAXSIZE)//插入后后串长>最大长度,不过串t可以全部插入
{
// printf("2调用\n");
for(i=MAXSIZE-1;i>=t.length+pos;i--)//和上面唯一不同的就是初始条件变了,上面是从插入后的最后一个位置开始的,所以既然插入后已经到达最大长度了,那么就直接用最大长度当初始条件就行了
{
s.str[i]=s.str[i-t.length];//还是一样的
}
for(i=0;i<t.length;i++)//这个和上面是一样的
{
s.str[i+pos]=t.str[i];
}
s.length=MAXSIZE;//更新长度,这时候就方便一些了
}
else//插入后后串长>最大长度,不过串t不可以全部插入
{
// printf("3调用\n");
for(i=0;i<MAXSIZE-pos;i++)//这时候就不用原来串中元素往后移了,最大长度和pos之间有多长,循环就有几次
{
s.str[i+pos]=t.str[i];
}
s.length=MAXSIZE;//更新长度,这时候就和上面一样方便了
}
printf("插入后的串长为:%d\n",s.length);
printf("插入后的串是:");
printf("%s\n",s.str);
}
//求串长操作
int StrLength(SeqString s)
{
int i=0;
while(s.str[i]!=0)//元素不为零就加一,一直加到元素为零为止
{
i++;
}
s.length=i;
printf("串s的长度为%d\n",s.length);
return s.length;
}
//串连接操作
int StrConcat(SeqString *s,SeqString t)
{
int i;
s->length=strlen(s->str);
t.length=strlen(t.str);
if(s->length+t.length>MAXSIZE)
{
printf("连接后的串长超过最大长度\n");
return 0;
}
else
{
for(i=s->length;i<s->length+t.length;i++)
{
s->str[i]=t.str[i-s->length];
}
}
s->length+=t.length;
printf("两串连接后的长度为%d\n",s->length);
printf("连接后的串是:%s\n",s->str);
return 1 ;
}
//顺序串的删除操作
void StrDelete(SeqString *s,int pos,int len)
{
int i;
if(pos>s->length||pos+len-1>s->length)
{
printf("删除位置不正确或要删除的字符数量太多了\n");
}
else if(pos<0||len<0)
{
printf("参数输入有误\n");
}
else
{
/*for(i=pos-1;i<pos+len-1;i++)
{
s->str[i]=s->str[i+len];
}算法设计有问题*/
for(i=pos+len-1;i<s->length;i++)
{
s->str[i-len]=s->str[i];
}
s->length=s->length-len;
s->str[s->length]='\0';
printf("删除后的串是:");
printf("%s\n",s->str);
}
}
//取子串操作
SeqString *SubString(SeqString s,int pos,int len)
{
int i;
SeqString *r;//新开一个r来存储取出的字串
if(s.length<=0)
{
printf("无子串可取!!\n");
return NULL;
}
else
{
r=(SeqString *)malloc(sizeof(SeqString));//这个地方最后调试的时候改一下
for(i=pos-1;i<pos+len-1;i++)
{
r->str[i-pos+1]=s.str[i];
r->length=len;
r->str[r->length]='\0';
}
}
printf("取出的子串是:");
printf("%s\n",r->str);
return r;
}
int main()
{
SeqString x,y;
char a[MAXSIZE],b[MAXSIZE];
int a_len,b_len,pos,len,i=1;
while(i)//保证一直进行
{
printf("-------------------------------------\n");
printf(" Main Menu \n");
printf(" 1 求串长 \n");
printf(" 2 插入一个串 \n");
printf(" 3 连接一个串 \n");
printf(" 4 删除子串 \n");
printf(" 5 取子串 \n");
printf(" 6 清屏 \n");
printf(" 0 结束程序 \n");
printf("--------------------------------------\n");
printf("请输入你选择的菜单号<1, 2, 3, 4, 5, 6, 0>:\n");
scanf("%d",&i);
switch(i)
{
case 1:
printf("请输入串:");
scanf("%s",a);
strcpy(x.str,a);
x.length=StrLength(x);
//printf("%d",x.length);
break;
case 2:
printf("请输入原来的串:");
scanf("%s",a);
strcpy(x.str,a);
x.length=StrLength(x);
printf("%d",x.length);
printf("请输入要插入的新串:");
scanf("%s",b);
strcpy(y.str,b);
y.length=StrLength(y);
printf("%d",y.length);
printf("请输入要插入的位置:");
scanf("%d",&pos);
StrInsert(x,pos,y);
break;
case 3:
printf("请输入前串:");
scanf("%s",a);
strcpy(x.str,a);
//StrLength(x);
x.length=StrLength(x);
printf("请输入后串:");
scanf("%s",b);
strcpy(y.str,b);
y.length=StrLength(y);
StrConcat(&x,y);
break;
case 4:
printf("请输入串:");
scanf("%s",a);
strcpy(x.str,a);
x.length=StrLength(x);
printf("从什么地方开始删除?\n");
scanf("%d",&pos);
printf("要删除多长的子串?\n");
scanf("%d",&len);
StrDelete(&x,pos,len);
break;
case 5:
printf("请输入串:");
scanf("%s",a);
strcpy(x.str,a);
x.length=StrLength(x);
printf("从什么地方开始取子串?\n");
scanf("%d",&pos);
printf("要取出多长的子串?\n");
scanf("%d",&len);
SubString(x,pos,len);
break;
case 6:
system("cls");
break;
case 0:
exit(0);
break;
default:
printf("输入有误~");
}
}
return 0;
}