数据结构课程设计.docx
《数据结构课程设计.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计.docx(21页珍藏版)》请在冰豆网上搜索。
![数据结构课程设计.docx](https://file1.bdocx.com/fileroot1/2023-1/7/4c100bf3-ca9e-45f9-8c7c-26e834f9d33f/4c100bf3-ca9e-45f9-8c7c-26e834f9d33f1.gif)
数据结构课程设计
数据结构课设报告
学生姓名苗帅
所在院系计算机科学与技术学院
专业计算机科学与技术
学号1413022024
指导教师管老师
南通大学计算机科学与技术学院
2016年1月13日
《数据结构》课程设计题目三:
约瑟夫(Jonseph)环
设计目的:
1.掌握单向循环链表的建立。
2掌握单项循环链表的操作。
设计的内容:
编号是1,2,……….,n的n个人按照顺时针的方向围坐一圈,每个人只有一个密码(正整数)。
一开始任选一个正整数作为报数的上限值m,从第一个人开始顺时针方向自1开始顺序报数,报到m停止报数。
报m的人出列,将他的密码作为新的m值,从他的顺时针方向的下一个人开始重新从1报数,如此下去直到所有的人全部出列为止。
请设计一个程序求出出列的顺序。
设计的要求:
1.利用单项的循环链表储存结构模拟此过程,按照出列的顺序输出个人的编号。
2.测试的数据:
m的初值为20,n=7,7个人的密码依次是3,1,7,2,4,7,4,首先m=6,则正确的输出是什么?
3.输入的数据:
建立输入函数的处理输入的数据,输入m的初值n,输入每个人的密码,建立单向的循环链表。
4.输出的形式:
建立一个输出的函数,将正确的出列顺序输出。
需求分析:
我们需要对单链表中存储的数据做出一点改动,除了每个人的number之外,还需要加上密码,并且无头指针,对名义上的头指针赋值。
概要设计:
这题采用的是线性表中的单向循环链表存储的结构,选择它作为存储结构是因为它的报数是一个循环的结构,而单向循环链表是可以依次循环访问的。
此处用了链表基本的几个函数,例如构造,析构,创建函数,删除,等一些基本的函数。
其中查找函数是为了删除链表中的元素用的。
函数是顺序调用的。
详细设计:
数据存储:
循环单链表存储信息。
构造函数:
创建一个头结点,此头结点将会在创建过程中存储信息,创建一个空的单循环的链表。
析构函数:
在程序的最后自动调用来清空表的。
创建函数:
创建过程中第一个结点(即存储信息的头结点)赋值,之后将每个人的密码输入,并且对所有结点编号。
查找函数:
是按照链表中所存的密码查找的,返回值是这个数的在链表中所在的位置。
删除函数:
以指针tail作为入口访问链表并输出和删除。
(此时的tail指向链表的左后一个位置)
C++代码:
#include
usingnamespacestd;
structLinkNode
{
intdata,num;
LinkNode*next;
};
classCLinkList
{
private:
LinkNode*tail;//不用头结点,直接用首结点,便于计数。
public:
CLinkList();
boolAppend(int,int);
boolDelete(int);
};
//构造函数
CLinkList:
:
CLinkList()
{
tail=NULL;
}
//尾部插入模板,用于输入数据的保存
boolCLinkList:
:
Append(inte1,inte2)
{
LinkNode*p=newLinkNode;
p->data=e1;
p->num=e2;
if(tail==NULL)//省略此步骤,tail则变为头指针。
{
tail=p;
tail->next=tail;
}
else
{
p->next=tail->next;
tail->next=p;
tail=p;
}
returntrue;
}
voidCreat(CLinkList&y,int&n)//不在类内
{
inta1,a2,i;
cout<<"请输入"<"<for(i=1;i<=n;i++)
{
cin>>a1;
a2=i;
y.Append(a1,a2);
}
}
//删除函数模板,用于保存编号、密码和删除
boolCLinkList:
:
Delete(intm)
{
LinkNode*p=tail,*q;
while(p!
=p->next)
{
for(intk=1;kp=p->next;
q=p->next;
p->next=q->next;
cout<num<<"";
m=q->data;
deleteq;
}
cout<num<<"";
deletep;
returnm;
};
intmain(){
CLinkListy;
intn,m;
cout<<"请输入参与人数n:
"<cin>>n;
cout<<"请输入第一个上限m:
"<cin>>m;
Creat(y,n);
m=y.Delete(m);
return0;
}
测试结构及展示:
测试以及调试过程中的一些问题:
1.经常因为头指针导致在测试的时候出现访问越界和重复删除的情况,造成程序崩溃。
后来为了避免头指针带来的问题,我开始把头指针去掉,即将头结点进行赋值。
当然也在初始化的操作过程中带来不便。
2.在删除过程中常常会找错位置重复删除。
小结:
我觉的我的突出问题是,拿到问题不是把他想清楚,做出设计,而是上来就做,在做的过程中改动,这样常常会导致返工。
会做,但是思路不清晰。
清晰的思路远比编码的过程中要。
《数据结构》课程设计题目四:
文学研究助手的实现
设计目的:
1.实现串类型的实现方法和文本匹配的方法.
2.熟悉一般文字处理软件的设计方法。
设计内容:
文学研究人员需要统计某篇英文小说某些形容词的出现次数和位置。
试写一个实现这一目标的文字统计系统,称为“文学研究助手”;
设计要求:
1.小说存于一个文本文件中。
2.待统计的词汇要一次输入完毕。
3.程序的输出的结果是每个词的出现次数和出现位置所在行的行号,格式自行设计。
需求分析:
首先是要统计文中的关键词,第二强调所有的关键词要一次全部输入,实现匹配,同时应该考虑到大小写的问题。
详细设计:
1.将所有的大写全部转化为小写,为了避免源文件中的数据被更改,我将小写之后的数据存到了一个新的txt文件中,在程序的最后删除掉即可。
2.之后将所有的待匹配的字符串全部写到一个数组里面,在我的程序设计中该数组不是很大,可根据的具体需求自行设计。
3.字符串的匹配,每当读入一个关键词,之后在全文中匹配,每次读取一行在中查找,找到位置。
有几个关键词就遍历文本中的文件几次。
C++代码:
#include
#include
#include
usingnamespacestd;
intmain()
{
charfrom[256],str[512],*p,ch,ch1;
cerr<<"小说所在位置";
cin.getline(from,256);
ifstreamin(from);
ofstreamout("garbage.txt");//将转换好了的文件写出
if(!
in){cerr<<"不能打开文件!
\n";exit(0);}
if(!
"garbage.txt"){cerr<<"不能打开文件!
\n";exit(0);}
while(in.get(ch))/判断第一行开头的字符,是字母则转换,否则不转换
{
if(65<=ch&&ch<=90)
{
out<break;
}
elseout<}
while(in.get(ch))
{
out<if(ch==''||ch=='\t'||ch=='\n'||ch==','||ch=='.'||ch=='')
{
in.get(ch1);
if(65<=ch1&&ch1<=90)
out<elseout<}
if(ch=='\n')//判断下一行开头的字符
{
while(in.get(ch))
{
if(97<=ch&&ch<=122)
{
out<}
else
out<break;
}
}
}
in.close();
out.close();//分界限
chartext[60];
intm2=0;//开始时的位置
intline=1,count=0,count1=0;
cout<<"待查找的关键字:
(请您输入小写的英文单词,小说中的大写单词将会被找到)";
cin.getline(text,60);
for(inti=0;;i++)
{
if(text[i]==''||text[i]=='\0')
{
cout<<"关键字是:
";
for(intm=m2;m
cout<cout<ifstreamin2("garbage.txt");
if(!
in2){cerr<<"不能打开文件!
\n";exit(0);}
while(!
in2.eof())//当未处理到文件末尾时继续处理
{
in2.getline(str,512,'\n');
for(intk=0;str[k]!
='\0';k++)
{
intkk=k;//传递当前的的位置
for(intm3=m2;m3
{
if(text[m3]==str[kk])
{
count1++;
kk++;
}
else
break;
}
if(count1==(i-m2))
{
count++;
cout<count1=0;
}
else
count1=0;
}
line++;
}//读进来
in2.close();
cout<<"共"<m2=i+1;
count=0;
line=1;//line重置
}//if判断
if(text[i]=='\0')
break;
}//for循环
remove("garbage.txt");//删除文件的操作
return0;
}//对每一个功能测试最后整合
测试用例:
Iloveyousomuch.Butyoudonotknow.
Iloveyousomuch.Butyoudonotknow.
Iloveyousomuch.
关键词的测试应该具有代表性。
myknowdonotsomuchhmuch
测试结果:
设计缺陷:
在写程序时候未考虑匹配的回溯问题,在匹配关键词的长度较大时会增加匹配的次数,这里可以对关键词写next[]函数。
小结:
老师也看到在向您讲的过程中发现了错误并改正,老师也告诉我合作的重要性,平时在编码是单打独斗比较多。
是不可取的,
自己也希望自己以后和同学多交流。
《数据结构》课程设计题目五:
一元稀疏多项式计算器
设计目的:
1.掌握稀疏矩阵的相关运算
2.掌握广义表的相关操作
设计内容:
设计一个一元稀疏多项式简单计算器
设计要求:
一元稀疏多项式简单计算器的基本功能是:
1.建立并输入多项式
2.输出多项式,输出形式为整数序列,nc1,e1,c2,e2,…,en,其中n是多项式的项数ci和ei分别是多项式的系数和指数,序列按指数降幂序列。
3.多项式a和b相加,建立a+b;
4.多项式a和b相减,建立a-b;
需求分析:
实现简单的多项式的加法,就是一个归类查找的方法,将指数相同的多项式进行加减的过程。
概要设计:
采用单链表的存储方式,首先设置结构体数组初始化单链表,设置一个结构体里面存储着系数和指数,建立类,生成头结点。
产生单链表。
函数有基本的构造,析构函数,清空链表的函数和加法函数,减法函数,显示函数,和排序函数。
详细设计:
AB中各有一个可以自由移动的指针,彼此不相关。
1.结构体里面存储多项式的系数和指数;
2.返回链表头指针的函数。
3.清空链表函数:
清空链表的函数需要一个返回链表的头指针的函数,这样头指针作为清空链表函数的形参,清空掉链表。
4.排序函数:
就是以指数为基础重新创建链表的过程。
实质上是一个冒泡排序的过程,以单链表最后一个结点next是NULL为标志,两次遍历链表,进行冒泡排序。
5.加法函数:
首先对输入的无序链表进行排序,然后将两个链表合成一个链表的。
其中A、B两个链表中的指数依次对比只有3种情况,一是小于,而是大于,三是等于
1.小于是A中的多项式指数比B中的顺序的相应位置小且无相同指数的项,则此时B中无项可以和A中的多项式相加,只是移动工作的指针即可。
2.大于是A中多项式指数比B中顺序的相应位置大且无相同指数的项,则将B中相应结点插入到A中。
移动工作指针。
3.等于是A对应位置的多项式指数和B中对应的位置相同时。
此时将系数加起来,如果等于0了就删除掉两个结点,如果不为0就整合到A链表上就好了。
最后移动工作的指针。
6.减法函数:
建立在加的基础上:
1.当B中的多项式在A中没有时候,将B链表的结点移动到A链表上,并且系数变为负数。
2.当A中的多项式在B中没有时候,保持多项式不变。
3.当A中B中多项式的指数相等时,将加法函数的sum值改为A链多项式中系数的值-B链中多项式系数的值之后步骤参照加法中相等时的处理办法。
C++代码实现:
#include
#include"process.h"
usingnamespacestd;
#defineMax20
typedefstruct
{
floatcoef;
intexp;
}PolyArray[Max];
voidInput(PolyArraya,intn)
{
for(inti=0;i{
cout<<"请输入第"<
cin>>a[i].coef>>a[i].exp;
}
}
structPolyNode
{
floatcoef;//数
intexp;//指数
PolyNode*next;
};
classPoly
{
private:
PolyNode*head;
public:
Poly();//构造函数,建立空多项式
~Poly();//析构函数,释放多项式
voidCreate(PolyArraya,intn);//键盘输入,创建多项式链表
voidDisp();//多项式显示
voidSort();//有序表排序
voiddxi(PolyNode*h);
PolyNode*mm();
voidAdd(PolyLB);//多项式加
voidSubstract(PolyLB);//多项式减
};
Poly:
:
Poly()
{//创建一空多项式
head=newPolyNode;
head->next=NULL;
}
Poly:
:
~Poly()
{
}
PolyNode*Poly:
:
mm()
{
returnhead;
}
voidPoly:
:
dxi(PolyNode*h)
{
PolyNode*p;
while(h)
{
p=h;h=h->next;deletep;
}
}
voidPoly:
:
Disp()
{
PolyNode*p;
p=head->next;
while(p!
=NULL)
{
cout<coef<<"x^"<exp<<'\t';
p=p->next;
}
cout<}
voidPoly:
:
Create(PolyArraya,intn)
{
PolyNode*s,*r;
inti;
r=head;
for(i=0;i{
s=newPolyNode;
s->coef=a[i].coef;
s->exp=a[i].exp;
s->next=NULL;
r->next=s;
r=s;
}
}
voidPoly:
:
Sort()
{
PolyNode*p,*q,*r;
p=head->next;
if(p!
=NULL)
{
r=p->next;//r指向p的后继结点
p->next=NULL;//构造只有一个结点的有序表
p=r;
while(p!
=NULL)
{
r=p->next;
q=head;
while(q->next!
=NULL&&q->next->expexp)
q=q->next;//在有序表中插入*p的前驱结点*q
p->next=q->next;//*p插入到*q之后
q->next=p;
p=r;
}
}
}
voidPoly:
:
Add(PolyLB)//前提是两个链表都是有序的
{
floatsum;
PolyNode*pa,*pb,*qa,*qb;//工作指针
pa=head;//当前对象的头结点
qa=pa->next;
pb=LB.head;
qb=pb->next;
while(qa!
=NULL&&qb!
=NULL)//有一个表为空就结束。
{
if(qa->expexp)
{//
pa=qa;qa=qa->next;
}
elseif(qa->exp>qb->exp)
{//
pb->next=qb->next;
qb->next=qa;
pa->next=qb;
pa=qb;
qb=pb->next;
}
else
{//
sum=qa->coef+qb->coef;
if(sum==0)//和为0的情况
{//
pa->next=qa->next;
deleteqa;
qa=pa->next;
pb->next=qb->next;
deleteqb;
qb=pb->next;
}
else//和不为0时
{
qa->coef=sum;
pa=qa;qa=qa->next;
pb->next=qb->next;
deleteqb;
qb=pb->next;
}
}
}
if(qb!
=NULL)
qa->next=qb;
}
voidPoly:
:
Substract(PolyLB)
{
floatsum;
PolyNode*pa,*pb,*qa,*qb;
pa=head;
qa=pa->next;
pb=LB.head;
qb=pb->next;
while(qa!
=NULL&&qb!
=NULL)
{
if(qa->expexp)
{
pa=qa;qa=qa->next;
}
elseif(qa->exp>qb->exp)
{
pb->next=qb->next;
qb->next=qa;
qb->coef=-qb->coef;//和加法的差别
pa->next=qb;
pa=qb;
qb=pb->next;
}
else
{
sum=qa->coef-qb->coef;//改成“-”号
if(sum==0)
{
pa->next=qa->next;
deleteqa;
qa=pa->next;
pb->next=qb->next;
deleteqb;
qb=pb->next;
}
else
{
qa->coef=sum;
pa=qa;qa=qa->next;
pb->next=qb->next;
deleteqb;
qb=pb->next;
}
}
}
if(qb!
=NULL)
qa->next=qb;
}
intmain()
{
intm1,m2,n;
PolyLA,LB;
PolyArraya;
PolyArrayb;
cout<<"多项式1的项数"<cin>>m1;
Input(a,m1);
cout<<"多项式2的项数"<cin>>m2;
Input(b,m2);
LA.Create(a,m1);
LB.Create(b,m2);
cout<<"原多项式A为:
";
LA.Disp();
cout<<"原多项式B为:
";
LB.Disp();
LA.Sort();
LB.Sort();
cout<<"有序多项式A为:
"