数据结构课程设计文章编辑集合运算.docx
《数据结构课程设计文章编辑集合运算.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计文章编辑集合运算.docx(31页珍藏版)》请在冰豆网上搜索。
![数据结构课程设计文章编辑集合运算.docx](https://file1.bdocx.com/fileroot1/2022-11/25/ced4a835-7236-45c9-89a1-f122b9dac8c4/ced4a835-7236-45c9-89a1-f122b9dac8c41.gif)
数据结构课程设计文章编辑集合运算
学号
成都理工大学
数据结构课程设计
设计说明书
题目
文章编辑集合运算
起止日期:
学生姓名
班级
成绩
指导教师(签字)
计算机科学与技术系
文章编辑
一、需求分析
1.问题描述
输入一页文字,程序可以统计出文字、数字、空格的个数。
2.基本要求
静态存储一页文章,每行最多不超过80个字符,共N行,要求:
(1)分别统计出其中英文字母数和空格数及整篇文章总字数;
(2)统计某一字符串在文章中出现的次数,并输出该次数;
(3)删除某一子串,并将后面的字符前移。
存储结构使用线性表,分别用几个子函数实现相应的功能。
输入数据的形式和范围:
可以输入大写、小写的英文字母、任何数字及标点符号。
输出形式:
(1)分行输出用户输入的各行字符;
(2)分4行输出"全部字母数"、"数字个数"、"空格个数"、"文章总字数"
(3)输出删除某一字符串后的文章;
3.需求分析
(1)将文本转换为链表储存。
(2)统计各个字符数量。
(3)能够将该链表打印出来,并且执行删除某一节点的操作。
(4)查找并匹配字符串,并得到对应的位置。
4.开发环境
系统环境:
MicrosoftWindows®10专业版
开发环境:
MicrosoftVisualStudio2015
开发平台:
Win64
开发语言:
C++
编译器:
Intel®ParallelStudioXE2013
硬件环境:
(1)CPU:
IntelCorei7-4710MQ
(2)内存:
16GB
(3)显示卡:
NVIDIAGeForceGTX960M
二、概要设计
1.流程图
2.结构体构造
本程序采用的数据结构是单链表形式,在每个节点中存储一个字符,用指针的方式连接,形成链表,通过遍历的方式来打印和搜寻所需的字符。
3.设计思想
本程序旨在处理文字,重点即是先将文本转化为链表存储,然后用对应的函数遍历链表,得出字符的数值。
使用KMP算法查找对应的字符串,并使用删除节点的方式完成字符串的删除操作。
三、详细设计
1.结构体构造
//构造存储字符的结构体
typedefstructlistNode{
charword;
structlistNode*next;
}wordList,*list;
//构造储存字符数量的结构体
typedefstruct{
intalpha;
intdigit;
intblank;
intsum;
}numStruct,*numNode;
//构造储存字符位置的结构体
typedefstructposNode{
intpos;
structposNode*next;
}posStruct,*posList;
2.函数构造
//线性链表初始化函数:
链表头指针
intwordList_init(list*res);
//存储结构初始化函数:
结构指针
intnumNode_init(numNode*num);
//字符位置链表初始化函数:
结构指针
intposNode_init(posList*posP);
//字符位置链表增加与储存函数:
头指针,插入字符
intposNode_add(posList*posP,intposNum);
//链表增加与储存函数:
头指针,插入字符
intwordList_add(list*res,charletter);
//文本转换链表函数,同时计算文本中的字符类别和数量:
链表头指针,结构体指针
inttext_transform(list*res,numNode*num);
//删除链表的某一节点:
该节点的前一个节点的指针
intwordList_delete(list*now);
//链表打印:
头指针
voidwordList_print(list*res);
//计算next数组的值:
voidnextArray_make(charstrFind[],intnext[]);
//KMP算法:
intKMP(charstrRes[],charstrFind[],intnext[]);
//KMP统计出现次数
intstringRepeat_count(charstrRes[],charstrFind[],posList*posL);
//字符串查询:
链表头指针,结构
voidstring_search(list*res,numNode*num);
//字符串删除函数:
链表头指针,结构
voidstring_delete(list*res,numNode*num);
//菜单函数
voidmenu();
3.重点函数分析
在这个程序当中,个人认为最重要的部分就是KMP算法的实现,这个算法的搜索速度极其快速,但是因为不太容易理解,所以实现上有些困难。
KMP算法相对于普通的搜索算法,最大的优势就是使用了一个next数组来帮助算法程序跳转,通过减少比对时间来优化效率。
这个算法的核心也就是是next数组的求法。
Next数组保证每一次比对完成以后向后跳转的具体位置。
而KMP算法的核心即是计算字符串string,每一个位置之前的字符串的前面部分和后部分的公共部分的最大长度(不包括字符串本身,否则最大长度始终是字符串本身)。
这样构造的算法可以在最大程度上向后跳转节约时间。
四、调试与测试
在调试本程序时,为了保证输入输出的值的正确,基本思路是在每个函数写好以后对该函数的效果进行测试,保证该函数能正常运行并得出对应正确的结果,并且对可能会影响到的指针的值进行处理,保证程序的健壮性。
如果程序出现了致命的错误,我就会打开断点调试功能筛查是哪个地方出了问题,然后进行修改。
五、执行结果
本程序所需要的文章以文本形式放在程序同目录下的input_text.txt内。
打开程序时会自动加载转换本文本,并且不会对原文本进行更改。
以下是演示图片。
六、源代码
#include
#include
#include
//构造存储字符的结构体
typedefstructlistNode{
charword;
structlistNode*next;
}wordList,*list;
//构造储存字符数量的结构体
typedefstruct{
intalpha;
intdigit;
intblank;
intsum;
}numStruct,*numNode;
//构造储存字符位置的结构体
typedefstructposNode{
intpos;
structposNode*next;
}posStruct,*posList;
//线性链表初始化函数:
链表头指针
intwordList_init(list*res);
//存储结构初始化函数:
结构指针
intnumNode_init(numNode*num);
//字符位置链表初始化函数:
结构指针
intposNode_init(posList*posP);
//字符位置链表增加与储存函数:
头指针,插入字符
intposNode_add(posList*posP,intposNum);
//链表增加与储存函数:
头指针,插入字符
intwordList_add(list*res,charletter);
//文本转换链表函数,同时计算文本中的字符类别和数量:
链表头指针,结构体指针
inttext_transform(list*res,numNode*num);
//删除链表的某一节点:
该节点的前一个节点的指针
intwordList_delete(list*now);
//链表打印:
头指针
voidwordList_print(list*res);
//计算next数组的值:
voidnextArray_make(charstrFind[],intnext[]);
//KMP算法:
intKMP(charstrRes[],charstrFind[],intnext[]);
//KMP统计出现次数
intstringRepeat_count(charstrRes[],charstrFind[],posList*posL);
//字符串查询:
链表头指针,结构
voidstring_search(list*res,numNode*num);
//字符串删除函数:
链表头指针,结构
voidstring_delete(list*res,numNode*num);
//菜单函数
voidmenu();
//主函数
intmain(void){
menu();
return0;
}
//线性链表初始化函数:
链表头指针
intwordList_init(list*res){
(*res)=(list)malloc(sizeof(wordList));
if((*res)){
(*res)->next=NULL;
(*res)->word='';
return1;
}else{
printf("空间分配失败,请重试。
\n");
return0;
}
}
//存储结构初始化函数:
结构指针
intnumNode_init(numNode*num){
(*num)=(numNode)malloc(sizeof(numStruct));
if((*num)){
(*num)->alpha=0;
(*num)->digit=0;
(*num)->blank=0;
(*num)->sum=0;
return1;
}else{
printf("空间分配失败,请重试。
\n");
return0;
}
}
//字符位置链表初始化函数:
结构指针
intposNode_init(posList*posP){
(*posP)=(posList)malloc(sizeof(posStruct));
if((*posP)){
(*posP)->next=NULL;
(*posP)->pos=0;
}else{
return0;
}
}
//字符位置链表增加与储存函数:
头指针,插入字符
intposNode_add(posList*posP,intposNum){
while((*posP)->next){
(*posP)=(*posP)->next;
}
//分配空间
(*posP)->next=(posList)malloc(sizeof(posStruct));
if((*posP)->next){
(*posP)=(*posP)->next;
(*posP)->next=NULL;
(*posP)->pos=posNum;
return1;
}else{
printf("空间分配失败,请重试。
\n");
return0;
}
}
//链表增加与储存函数:
头指针,插入字符
intwordList_add(list*res,charletter){
while((*res)->next){
(*res)=(*res)->next;
}
//分配空间
(*res)->next=(list)malloc(sizeof(wordList));
if((*res)->next){
(*res)=(*res)->next;
(*res)->next=NULL;
(*res)->word=letter;
return1;
}else{
printf("空间分配失败,请重试。
\n");
return0;
}
}
//文本转换链表函数,同时计算文本中的字符类别和数量:
链表头指针,结构体指针
inttext_transform(list*res,numNode*num){
//文件操作,打开文件
FILE*fp;
fp=fopen("input_text.txt","r");
charletter;
//初始化链表
wordList_init(&(*res));
numNode_init(&(*num));
//重新声明变量,操作resNow来构建链表
listresNow=(*res);
//循环将文本读入线性表中
while((letter=getc(fp))!
=EOF){
wordList_add(&resNow,letter);
if(isalpha(letter))
(*num)->alpha++;//求字母数
elseif(isdigit(letter))
(*num)->digit++;//求数字个数
elseif(letter=='')
(*num)->blank++;//求空格数
(*num)->sum++;
}
//关闭文件
fclose(fp);
}
//删除链表的某一节点:
该节点的前一个节点的指针
intwordList_delete(list*now){
listtemp=(*now)->next;
(*now)->next=temp->next;
free(temp);
return1;
}
//链表打印:
头指针
voidwordList_print(list*res){
listtemp=(*res);
while(temp->next){
temp=temp->next;
printf("%c",temp->word);
}
}
//计算next数组的值:
voidnextArray_make(charstrFind[],intnext[]){
inti,j;
intlen=strlen(strFind);
next[0]=-1;//next[0]放上-1
i=0;//指向字符串每个字符的指针
j=-1;
while(iif(j==-1||strFind[i]==strFind[j]){//如果是第一个字符或遇到相同的字符
i++;
j++;
next[i]=j;
}
else
j=next[j];
}
//for(i=0;i//printf("%d",next[i]);
//}
}
//KMP算法:
intKMP(charstrRes[],charstrFind[],intnext[]){
inti,j;
i=j=0;
intlenRes=strlen(strRes);
intlenFind=strlen(strFind);
while(iif(j==-1||strRes[i]==strFind[j]){
i++;
j++;
}
else
j=next[j];
}
if(j==lenFind)
returni-lenFind;
else
return-1;
}
//KMP统计出现次数
intstringRepeat_count(charstrRes[],charstrFind[],posList*posL){
intlenRes=strlen(strRes);
intlenFind=strlen(strFind);
intlenTemp=0;
intrepeatCount=0;
char*strTemp;
intnext[lenRes];
nextArray_make(strFind,next);
intpos=KMP(strRes,strFind,next);
if(pos==-1){
return0;
}
strTemp=&(strRes[pos+lenFind]);
lenTemp=strlen(strTemp);
repeatCount=1;
printf("\n第%d次在第%d个位置出现。
\n",repeatCount,(pos+1));
intposCount=pos+1;
posListtempPOS=(*posL);
posNode_add(&tempPOS,posCount);
while(lenTemp>lenFind){
intnext[lenTemp];
nextArray_make(strFind,next);
intpos=KMP(strTemp,strFind,next);
if(pos==-1){
break;
}else{
strTemp=&(strTemp[pos+lenFind]);
lenTemp=strlen(strTemp);
repeatCount++;
posCount+=(pos+lenFind);
printf("\n第%d在第%d个位置出现。
\n",repeatCount,posCount);
posNode_add(&tempPOS,posCount);
}
}
returnrepeatCount;
}
//字符串查询:
链表头指针,结构
voidstring_search(list*res,numNode*num){
printf("\n请输入您想要查找的字符串:
\n");
//获得最大长度为文本文件大小的字符串数组
charstrFind[(*num)->sum];
scanf("%s",&strFind);
//将链表转换为数组处理
charstrRes[(*num)->sum];
listtemp=(*res);
inti=0;
while(temp->next){
temp=temp->next;
strRes[i]=temp->word;
i++;
}
posListpos;
posNode_init(&pos);
intrepeatCount=stringRepeat_count(strRes,strFind,&pos);
if(repeatCount){
printf("\n该字符串“%s”在本文本中出现了%d次。
",strFind,repeatCount);
}else{
printf("没有搜索到该文本。
");
}
}
//字符串删除函数:
链表头指针,结构
voidstring_delete(list*res,numNode*num){
printf("\n请输入您想要删除的字符串:
\n");
//获得最大长度为文本文件大小的字符串数组
charstrFind[(*num)->sum];
scanf("%s",&strFind);
//将链表转换为数组处理
charstrRes[(*num)->sum];
listtemp=(*res);
inti=0;
while(temp->next){
temp=temp->next;
strRes[i]=temp->word;
i++;
}
posListpos;
posNode_init(&pos);
intrepeatCount=stringRepeat_count(strRes,strFind,&pos);
if(!
repeatCount){
printf("没有搜索到该文本。
");
return;
}
printf("\n该字符串“%s”在本文本中出现了%d次。
\n",strFind,repeatCount);
printf("\n您确认删除这个字符串吗?
\n\n回复数字1来确认此操作。
\n");
i=0;
scanf("%d",&i);
if(i==1){
intcount=0;
listtemp=(*res);
pos=pos->next;
while(temp->next&&pos){
intlenDelete=strlen(strFind);
count++;
if(count==pos->pos){
count+=lenDelete;
while(lenDelete){
wordList_delete(&temp);
lenDelete--;
}
pos=pos->next;
}
temp=temp->next;
}
printf("\n\n删除成功,现文本如下:
\n\n");
wordList_print(&(*res));
}
return;
}
//菜单函数
voidmenu(){
//声明链表头指针
listres;
//声明数量结构体
numNodenum;
//将文本转换为链表保存并统计字符数量
text_transform(&res,&num);
intfunChoose;
while
(1){
printf("\n请输入序号来选择您需要的功能:
\n\n");
printf("1.显示文本\n\n2.显示字符统计情