舞伴问题说明书.docx
《舞伴问题说明书.docx》由会员分享,可在线阅读,更多相关《舞伴问题说明书.docx(18页珍藏版)》请在冰豆网上搜索。
![舞伴问题说明书.docx](https://file1.bdocx.com/fileroot1/2023-4/20/1bf24e98-582c-4212-9a73-d6d2ba10e3f0/1bf24e98-582c-4212-9a73-d6d2ba10e3f01.gif)
舞伴问题说明书
《数据结构与算法》
课程设计说明书
题目:
学院:
专业:
姓名:
学号:
指导教师:
2012年9月9日
目录
摘要......................................................3
引言3
1系统概述4
2需求分析4
2.1系统需求4
2.2开发环境4
3设计详解.............................................5
4所遇到的问题和分析解决15
5系统特色及关键技术16
6结论17
参考文献17
摘要
1.系统的主要任务
学生搭配问题内容是:
一班有m个女生,有n个男生(m不等于n),
现要开一个舞会.男女生分别编号坐在舞池的两边的椅子上。
每
曲开始时,依次从男生和女生中各出一人配对跳舞,本曲没成功
配对者坐着等待下一曲找舞伴。
应用循环队列来实现此程序。
2.设计方法
循环队列是一种环状的队列并且对头元素指向队尾元素,学
生搭配问题是典型的只有采用循环队列才能解决的问题,实验表
明该算法的空间复杂度优于其他算法,通过这次对学生搭配问题
的解决可以更好的理解和运用循环队列。
关键词:
数据结构;C语言;循环队列
引言
课程设计是实践性教学中的一个重要环节,它以某一课程为基础,可以涉及和课程相关的各个方面,是一门独立于课程之外的特殊课程。
课程设计是让同学们对所学的课程更全面的学习和应用,理解和掌握课程的相关知识。
《数据结构》是一门重要的专业基础课,是计算机理论和应用的核心基础课程。
数据结构课程设计,要求学生在数据结构的逻辑特性和物理表示、数据结构的选择和应用、算法的设计及其实现等方面,加深对课程基本内容的理解。
同时,在程序设计方法以及上机操作等基本技能和科学作风方面受到比较系统和严格的训练。
在这次的课程设计中我选择的题目是舞伴问题。
舞伴问题只是一个简单的队列运用,主要是为了方便一些小型的舞会,在寻找舞伴的问题上得到相应的解决,同时也方便在舞伴的配对不均衡的情况下,能够有效的,快速的解决这种现象,让每一个人都能够愉快地舞蹈。
其实这种舞伴问题是经常见到的,特别是在一些不是很正规的小型舞会,由于男女的不均衡,导致一些人没有机会参加跳舞。
有了这个系统之后就可以很好的安排这些舞伴的问题。
这样就可以安排到每一个人都可以参加跳舞了。
1系统概述
舞伴配对问题的它主要运用到的是循环队列,但是我这里的代码多运用了一个结构体的单链表,主要是用来记录男女是否跳过舞,方便你需要查找某男女是否跳过舞,以及在第几轮一起跳的。
为了比较美观一点我自己加了些图案进去,这样整体看上去比较有个性,而我这个代码主要是有一下的设计以及功能:
核心问题:
循环队列的应用
数据模型(逻辑结构):
循环队列(两个),将男生、女生两组人分别存放,以后实现循环配对输出。
存储结构:
循环链表。
核心算法:
循环队列的入队,出队,判队满,判队空。
输入数据:
男生人数、女生人数,歌曲数量
输出数据:
每一首歌曲播放时,男生和女生搭配情况(输出编号)
以及他们在下一首歌中,等待的第一个人是谁。
当要查找的男女搭配时输出歌曲编号,和他们搭配的总次数。
2需求分析
2.1系统需求
为了能够更好的实现舞伴的循环的配对,这里主要运用了结构体方式的循环队列。
因为循环队列是在队列的顺序存储结构中,除了用乙组地址连续的存储单元一次存放从队列头到队列尾的元素外,尚需附设两个指针front和rear分别指示队列头和队列尾元素的位置。
(1)要模拟动态地显示出现题目中所要求的循环,我们要先得定义两个队列的两个对象,Q1和Q2。
(2)将男生、女生两组人分别存入这两个队列。
以实现他们的配对输出,这是循环队列固有的特性。
(3)利用循环队列的特性,将男女生分别进行入队列和出队列操作,且实现搭配输出。
(4)循环队列的长度分别设为男女生的个数即可。
在计算机终端输出的结果是:
根据要求输出男生女生搭配情况。
舞伴配对问题的实现主要运用了一下的主要函数:
(1)初始化队列函数:
voidInitQueue(LinkQueue&Q)
(2)舞伴进队函数:
voidEnQueue(LinkQueue&Q,char*str)
(3)舞伴出队函数:
QueuePtrDeQueue(LinkQueue&Q,char*str)
(4)取队列中的对头函数:
voidGetHead(LinkQueueQ,char*str)
(5)实现舞伴的配对函数:
voidDancer(PListheader,LinkQueue&Q1,LinkQueue&Q2)
(6)保存出队舞伴信息函数:
PListList_insert(PListList_header,char*M,char*W,intc)
(7)查找舞伴信息函数:
PListList_find(PListList_header,char*M,char*W)
(8)比较舞伴信息函数:
boolcmp(PListp1,PListp2)
通过这些函数可以,可以实现舞伴的输入,自动配对舞伴,以及在舞会中某男女配对跳舞的情况。
2.2开发环境
一小段话点一下用于开发的环境(VC)和开发语言(C或C++)
3详细设计
3.1设计函数调用关系图
3.2主要函数的详解
(1)关键算法之一:
初始化队列
voidInitQueue(LinkQueue&Q)
{//构建一个空队列
Q.front=Q.rear=(QueuePtr)malloc(sizeof(QNode));
if(!
Q.front)
exit(0);
Q.front->next=Q.front;
}
函数主要是实现队列的初始化,为以后的结构体队列的对象进行初始化。
(2)关键算法之二:
入队函数
voidEnQueue(LinkQueue&Q,char*str)//将字信息入队
{
QueuePtrp;
p=(QueuePtr)malloc(sizeof(QNode));
if(!
p)
exit(0);
strcpy(p->name,str);
p->next=NULL;
Q.rear->next=p;
Q.rear=p;
}
函数主要进行信息的入队,通过调用strcpy(p->name,str)函数赋值存储跳舞者的信息,是用循环队列进行实现的。
在以后的函数中,只要进行对它的调用就可以实现它的功能。
舞者入队的展现界面:
(3)关键算法之三:
出队函数
QueuePtrDeQueue(LinkQueue&Q,char*str)//将结点删除后连接到队列的后方
{
QueuePtrp;
p=Q.front->next;
strcpy(str,p->name);
Q.front->next=p->next;
if(Q.rear==p)
Q.rear=Q.front;
returnp;
}
出队函数是用以链表删除的形式进行出队的,主要是通过节点的删除实现舞伴的出队功能,和队列的出队是一致的。
而这里我并没有直接的删除,只是让它返回一个值,方便后面可以进行信息的保存,当信息保存好后,然后我再free()掉。
舞者出队配对展现界面:
(4)关键算法之四:
取队头函数
voidGetHead(LinkQueueQ,char*str)//若队列非空,取队头元素
{
QueuePtrp;
if(Q.front!
=Q.rear)
{
p=Q.front->next;
strcpy(str,p->name);
}
取头函数主要是为了判断下一轮跳舞第一位是在等待的是谁。
直接通过结构体指针对象QueuePtrp指向队列的头来实现的。
取对头函数的界面展示:
(5)关键算法之五:
舞伴自动配对的实现函数
这里是通过定义两个LinkQueue&Q1,LinkQueue&Q2结构体队列的对象,然后用这两个对象分别进行对男女舞者的信息录入,这样直接就可以实现两个队列的使用,减省分别对男女舞者队列函数定义,这样使用更加的方便,扩展性也比较好,没有多大的限制,当你需要再次使用一个队列时。
直接可以通过它定义对象就好,没有必要在定义一个函数。
voidDancer(PListheader,LinkQueue&Q1,LinkQueue&Q2)
printf("&&&&&&&&请输入男舞伴的人数:
&&&&&&&&&*\n");
scanf("%d",&b);
ch=getchar();
printf("\n");
printf("&&&&&&&&请输入男舞伴的名字:
&&&&&&&&&*\n");
for(i=0;i
{
gets(str);
EnQueue(Q1,str);
printf("\n");}
printf("&&&&&&&请输入女舞伴的人数:
&&&&&&&&&&*\n");
scanf("%d",&g);
ch=getchar();
printf("\n");
printf("&&&&&&&请输入女舞伴的名字:
&&&&&&&&&&*\n");
for(i=0;i{
gets(str);
EnQueue(Q2,str);
printf("\n");
}
这里是进行男女舞者信息的入队,它是通过使用者首先进行对男女舞者的人数进行输入,以及舞者的姓名,再通过进行调用入队函数EnQueue(Q1,str)来进行男女舞者的入队,这里它使用之处在于它没有人数的限制,只要输入舞者的姓名,没有必要进行判断性别,把它们分别存储在两个队列当中。
printf("&&&&&&&请输入舞会的轮数:
&&&&&&&&&&&*\n");
scanf("%d",&ls);
if(bk=b;
else
k=g;
for(i=0;i{
printf("&&&&&&&第%d轮数配对如下:
&&&&&&&&&&*\n",i+1);
printf("&&&&&&&男生<-------------->女生&&&&&&&*\n");
for(j=0;j{temp1=DeQueue(Q1,boy);temp2=DeQueue(Q2,girl);//顺序出列跳舞
printf("&&&&&&&%s<>%s&&&&&&&*\n",boy,girl)
EnQueue(Q1,boy);
EnQueue(Q2,girl);//再次进入队列,等待下一轮
通过输入舞会的轮数来判断进行的轮次,然后判断男女舞者的双方,以人数较少的一方为循环出队的人数然后进行配对,进而判断出第一个等待的舞者是谁。
这里需要的只是判断语句来判断出每一轮有多少对舞者进行跳舞。
再通过调用入队函数EnQueue(Q1,boy);EnQueue(Q2,girl);进行再次入队,等待下一轮的舞伴的配对的开始。
。
配对的情况的界面展示:
(6)关键算法之六:
创建结构体链表
这个算法主要是为了存储每一轮舞会的信息,列如:
每一轮舞会某男女是否一起跳过舞,它们一起跳过几次,在哪一轮跳的。
而实现记录这些信息呢,我主要是运用到了单链表的插入,查找,以及比较三个函数功能来实现的。
然后通过结构体的对象来调用信息。
structnew_list
{
new_list*next;
charMan[10];
charWoman[10];
intcount;
};
typedefnew_list*PList;
//为指针申请节点并初始化节点函数
PListinit()
{
PListt=(PList)malloc(sizeof(new_list));
while(t==NULL)t=(PList)malloc(sizeof(new_list));
t->next=NULL;
t->count=0;
returnt;
}
这个只是一个方便函数而已,没有大多的使用性,只是方便我们在定义指针时,避开了再次为它申请节点初始化而已。
我们只需要通过调用这个函数就可以实现它的初始化,没有必要再次的为它重新的申请,这样程序就比较的简单明了,同时也可以节省了不少的时间。
//信息插入函数,
PListList_insert(PListList_header,char*M,char*W,intc)
{
PListtemp=List_header,L=init();
strcpy(L->Man,M);
strcpy(L->Woman,W);
L->count=c;
while(temp->next)
temp=temp->next;
temp->next=L;
returnList_header;
}
运用链表的插入来实现存储信息,这里不用判断插入的顺序,直接顺序的插入进去,也不用考虑是否有相同的信息。
这样下次进行比较时,就可以直接从头比较到尾,查找出我们需要查找的数据信息,以及它出现的次数,通过这样的存储方便了不是,程序也比较的简单实用。
//信息查找函数
PListList_find(PListList_header,char*M,char*W)
{
PListtemp=List_header->next;
while(temp){
inti=strcmp(temp->Man,M),j=strcmp(temp->Woman,W);
if(i==0&&j==0)returntemp;
temp=temp->next;
}
returnNULL;
}
通过使用者的输入需要查找的信息,来查找是否找到符合要求,这里只是需要一个简单的字符串比较和一个结构体链表的对象,让它从链表头开始查看比较是否存在符合要求的数据,当存在时,直接返回NULL;
//比较函数
boolcmp(PListp1,PListp2)
{
inti=strcmp(p1->Man,p2->Man),j=strcmp(p1->Woman,p2->Woman);
if(i==0&&j==0)
returntrue;
else
returnfalse;
}
多运用一个比较函数是为了能够进行数据的比较,看链表中是否存在有多少个符合要求的数据,由于我们需要查看某男女的配对的情况,所以我们得把他们的所有的情况都列出来,不能只能单一说出是否存在。
所以在运用查找函数判断是否存在的同时,进一步判断出他们每一次的情况。
(7)关键算法之七:
查找配对情况函数
voidcharge(PListheader,LinkQueueQ1,LinkQueueQ2)//查找x男和y女是否有跳过舞
{
printf("分别输入要查配对男生和女生的名字\n");
printf("********************************************************\n");
scanf("%s%s",&a,&b);
intconut=1,flag=0;
while(conut<=5)
{
list=List_find(h,a,b);
if(list)
{
while(h->next)
{
if(cmp(h->next,list))
printf("在第%d首歌时%s男生和%s女生一起过跳舞\n",h->next->count,a,b);
h=h->next;}
差找配对情况函数,主要是调用了结构体链表中的,查找函数和比较函数来实现的。
首先是调用查找函数List_find(h,a,b)查出是否存在符合输入信息的要求,如果有的话就继续调用比较函数if(cmp(h->next,list)),比较出用多少个符合要求的数据,然后一一的输出符合要求的数据。
如果查找不出的话,就直接跳过比较函数。
查找舞伴配对情况的界面展示:
演示界面
(8)关键算法之八:
主函数的设计
voidmain()
{
LinkQueueQ1,Q2;
PListheader=createlist();
InitQueue(Q1);
InitQueue(Q2);
Dancer(header,Q1,Q2);
定义对象,调用初始化队列的函数,然后调用舞伴配对的函数Danner();进行舞伴的配对。
这里只是一个函数的调用。
没有多大的难度和实际操作。
while(true)
{
printf("*****选择你的操作:
********\n");
printf("*****按1查询男女配对情况********\n");
printf("*****按3退出操作!
******\n");
fflush(stdin);
scanf("%d",&i);if(i==1||i==2||i==3){
switch(i)
{
case1:
charge(header,Q1,Q2);break;
case3:
exit(0);break;
}
为了能够比较美观一点,我这里运用switch(),进行选择的操作,比起用字符的判断的看起来更加的漂亮实用。
选择演示界面:
以上就是代码中比较核心的算法,以及运行的演示。
至于算法中各个函数的实现,不是一一的表达出来,只能说一些重要的算法的运算方式,对于我为什么要运用这种思路,主要是因为我个人觉得方便使用,还有一些是我为自己添加的代码是为了美感,没有多大的使用价值。
4所遇到的问题和分析解决
舞伴问题这一个题目当时还不知道是怎么回事,通过上网的查找以及借鉴终于知道编写舞伴问题的思路,使用队列进行。
但是在编写的过程中,判断队空,队满又是一个问题,经过自己的翻阅课本才解决。
但是最关键的问题是在舞伴配对的函数里,在最初的设计过程中犯一个错误,即没有很好的进行整体的布局,也没有定义统一的函数接口,以至程序的结构与函数的混乱。
不能够编译。
所以,我不得不又重新的分配任务,以及定义各个函数的接口。
所以,编写代码时要注意自己定义的函数,同时要考虑好自己所需要的布局,这样一来解决起来就比较的简单了。
还有在自己编写查找某男女的配对情况时,没有想到储存跳舞的信息,导致在查找配对时不能实现操作。
经过询问同学发现了问题的所在,所以在程序中我又使用了一个链表的结构体,是用来保存跳舞的信息的,temp1=DeQueue(Q1,boy);temp2=DeQueue(Q2,girl);header=List_insert(header,temp1->name,temp2->name,i+1)。
通过一个对象保存出队的信息,然后再调用链表的插入函数进行统一的保存,这样一来,我就可以随意的查找我所需要的信息了。
虽然信息保存下来了,但是要一一的查找里面的数据也是有个小问题,那就是字符串的比较,由于自己的习惯,没有注意到这个问题,于是就用到了“==”,虽然可以编译过了,但是没有自己想要的结果。
通过调试检查后,发现字符串应该用i=strcmp(p1->Man,p2->Man),j=strcmp(p1->Woman,p2->Woman)进行比较。
通过这次的课设也证实了自己所学,而问题的出现也是增加了自己的知识,同时也意识到作为一位编程员必须要有足够的耐心和细心来写自己的代码。
要有一个整体的布局构造。
5系统特色及关键技术
特色的代码应该算不上,但是我个人觉很是不错的地方和想法,虽然知识简单的几句代码,但是这是一个很重要的一部分,要是弄不好,整个程序就不会得到实现。
printf("&&&&&&&第%d轮数配对如下:
&&&&&&&&&&*\n",i+1);
printf("&&&&&&&男生<-------------->女生&&&&&&&*\n");
for(j=0;j{temp1=DeQueue(Q1,boy);temp2=DeQueue(Q2,girl);//顺序出列跳舞header=List_insert(header,temp1->name,temp2->name,i+1);
free(temp1);
free(temp2);
printf("&&&&&&&%s<>%s&&&&&&&*\n",boy,girl);
EnQueue(Q1,boy);
EnQueue(Q2,girl);//再次进入队列,等待下一轮
这里是舞伴配对时候,进行自动配对时的出队进队函数的调用,先出队再调用链表插入保存信息,然后再删除队列的节点,最后再次进队的全部循环过程。
所有过程缺一不可,过程中顺序也是不能打乱的,是一个十分需要注意的地方,需要我们思考的地方,也是整个代码的重要部分之一。
6结论
通过两周的学习洱海实践,解决实践问题(舞伴问题),让我对循环队列有了更深的了解,对计算机的言语有了更好的喜好和理解,同时也提高我对实际问题的解决能力。
我知道了当一段相同的代码在程序中多次的使用并且功能相对单一时,有必要将其写成一个函数,以减少工作量,并且使程序有更好的可读性。
在编写的过程中,及时对重要和难懂的程序段进行注释是一个很好的习惯,无论是以后的测试还是维护都能够节省相当多的时间。
调试是应该最先进行各函数的调试,确保没有什么错误时再进行各模块的的调试,最后才是将个模块组合在一起测试完整的程序。
在调试中不断的进行改进,完善。
在能够正确运行的基础上,再对各函数进行格式优化,加强程序的结构性,可读性,包括给运行界面增加相应的操作提示等,使操作界面简单明了又美观。
对于我们应该要不断的通过上机来提高自己的学习水平,在上机的同时改正了自己对某些算法的错误理解和使用,使自己在通过程序解决问题时抓住关键算法,有了自己的算大思路和流程图后,自己就可以用计算机的言语来编写自己的程序。
进而解决相应的实际问题了。
参考文献
[1]严蔚敏.吴伟民.数据结构(C语言版).北京:
清华大学出版社.1997.4.
[2]严蔚敏.吴伟民.米宁.数据结构题集(C语言版).北京:
清华大学出版社.1999.2.
[3]张乃孝.算法与数据结构.北京:
高等教育出版社.2002.
[4](美)BrianW.Kernighan,DennisM.Ritchie.C程序设计语言(第2版·新版).
机械工业出版社.2004.
[5]李丽娟.c/c++语言程序设计教程(从模块化到面向对象)(第3版).北京:
人民邮电出版社.2012.
[6]数据结构与算法分析(Java版),APracticalIntroductiontoDataStructuresandAlgorithmAnalysisJavaEditionCliffordA.Shaffer,张铭,刘晓丹译 电子工业出版社