数据结构课程设计报告约瑟夫环.docx
- 文档编号:30049762
- 上传时间:2023-08-04
- 格式:DOCX
- 页数:25
- 大小:439.38KB
数据结构课程设计报告约瑟夫环.docx
《数据结构课程设计报告约瑟夫环.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计报告约瑟夫环.docx(25页珍藏版)》请在冰豆网上搜索。
数据结构课程设计报告约瑟夫环
课程设计
课程名称:
程序设计、数据结构
课题名称:
约瑟夫环
班级:
学号:
姓名:
指导教师:
湖南理工学院计算机学院
2011年12月
一、问题描述
约瑟夫环问题描述的是:
设编号为1,2,…,n的n(n>0)个人按顺时针方向围坐一圈,每个人持有一正整数密码。
开始时选择一个正整数作为报数上限m,从第一个人开始顺时针方向自1起顺序报数,报到m时停止报数,报m的人出圈,将他的密码作为新的m值,从他在顺时针方向上的下一个人起重新从1报数。
如此下去,直到所有人都出圈为止。
令n最大值为100。
要求设计一个程序模拟此过程,求出出圈的编号序列。
如下图分析:
二、逻辑设计
1、循环链表抽象数据类型定义
typedefstructLNode//定义单循环链表中节点的结构
{
intnum;//编号
intpwd;//password
structLNode*next;//指向下一结点的指针
}LNode;
2、本程序包含一下几个模块
(1)构造结点模块
LNode*createNode(intm_num,intm_pwd)
{
LNode*p;
p=(LNode*)malloc(sizeof(LNode));//生成一个结点
p->num=m_num;//把实参赋给相应的数据域
p->pwd=m_pwd;
p->next=NULL;//指针域为空
returnp;
}
(2)创建链表模块
voidcreateList(LNode*ppHead,intn)
(3)出队处理模块
voidjose(LNode*ppHead,intm_pwd)
(4)约瑟夫环说明输出模块
voidinstruction()
(5)菜单模块
voidmenu()
(6)主函数模块
intmain()
函数的调用关系图如下:
三、详细设计
1.主函数
根据流程图,主函数程序如下:
intmain()
{
intn,m,x;
LNode*ppHead=NULL;
menu();
for(;;){
printf("\n请选择要执行的操作:
");
scanf("%d",&x);
system("cls");
switch(x){
case1:
printf("****************************************************************\n");
printf("约瑟夫环:
\n");
printf("编号为1,2,3,4…,n的n个人按顺时针方向围坐一圈,每人持有一个密\n");
printf("码(正整数).一开始任选一个正整数作为报数的上限值m,从第一个人开始\n");
printf("按顺时针方向自1开始顺序报数,报到m时停止.报m的人出列,将他的密码\n");
printf("m作为新的m值,从他在顺时针方向上的下一人开始重新从1报数,如此下去,\n");
printf("直到所有人全部出列为止.编程打印出列顺序.\n");
printf("****************************************************************\n");
main();
break;
case2:
printf("\n请输入总人数n:
");
scanf("%d",&n);
printf("请输入开始上限数m:
");
scanf("%d",&m);
createList(&ppHead,n);
printf("\n");
printf("出队顺序:
\n");
jose(ppHead,m);
printf("\n约瑟夫环游戏结束!
\n");
main();
break;
case0:
exit(0);
default:
system("cls");
printf("\n您选择的操作有误,请重新选择...\n\n\n");
main();
}
}
return0;
}
2.链表的创建
/*创建单向循环链表ppHead,人数个数为n,并输入每个人的密码值,若建立失败则生成头结点,让cur指向他,若建立成功则插入结点P,cur指向的数据元素为p,后续为"空"的节点,再把P插入循环链表ppHead中*/
根据流程图,创建链表函数程序如下:
voidcreateList(LNode**ppHead,intn)
{
inti,m_pwd;
LNode*p,*cur;//cur:
浮标指针
for(i=1;i<=n;i++)
{
printf("输入第%d个人的密码:
",i);
scanf("%d",&m_pwd);//输入持有密码
p=createNode(i,m_pwd);//调用构造结点函数
if(*ppHead==NULL)//如果头结点为空
{
*ppHead=cur=p;//生成头结点,让cur指向他
cur->next=*ppHead;//cur的指针域指向自身
}
else//如果不为空,则插入结点
{
p->next=cur->next;
cur->next=p;
cur=p;//cur指向新插入结点
}
}
printf("完成创建!
\n");//提示链表创建完成
}
3.出队处理
/*p指向要删除节点的前一个节点,ppHead指向要删除的节点,使p=ppHead,ppHead再指向要删除节点的下一个节点,使p和ppHead链接,输出p指向节点的编号和密码值,释放ppHead,如此循环,直至把所有节点都打印和删除为止!
*/
根据流程图,出队函数程序如下:
voidjose(LNode*ppHead,intm_pwd)
{
inti,j;
LNode*p,*p_del;//定义指针变量
for(i=1;p!
=ppHead;i++){
for(j=1;j p=ppHead;//p赋值为ppHead,p指向要删除结点的前一个结点 ppHead=ppHead->next;//ppHead指向下一个元素 } p->next=ppHead->next;//p结点与头结点链接 i=ppHead->pwd;//i赋值为ppHead->pwd j=ppHead->num;//j赋值为ppHead->num,j为要删除的密码值 printf("第%d个人出列,密码: %d\n",j,i); m_pwd=ppHead->pwd;//m_pwd赋值为ppHead->pwd free(ppHead);//释放头结点 ppHead=p->next;//ppHead重新赋值给p->next,即释放前的ppHead->pwd指针//删除报数结点 } i=ppHead->pwd;//i赋值为ppHead->pwd j=ppHead->num;//j赋值为ppHead->num printf("最后一个出列是%d号,密码是: %d\n",j,i); free(ppHead);//释放头结点 } 4.约瑟夫环说明模块 voidinstruction() { printf("****************************************************************\n"); printf("约瑟夫环: \n"); printf("编号为1,2,3,4…,n的n个人按顺时针方向围坐一圈,每人持有一个密\n"); printf("码(正整数).一开始任选一个正整数作为报数的上限值m,从第一个人开始\n"); printf("按顺时针方向自1开始顺序报数,报到时停止.报m的人出列,将他的密码\n"); printf("m作为新的m值,从他在顺时针方向上的下一人开始重新从1报数,如此下去,\n"); printf("直到所有人全部出列为止.编程打印出列顺序.\n"); printf("******************************************************\n"); return0; } 5.菜单模块 voidmenu(){ printf("**************************约瑟夫环*****************************\n"); printf("\n"); printf("[1]约瑟夫环问题的阐述\n"); printf("[2]按要求求解约瑟夫环\n"); printf("[0]退出\n"); printf("**************************欢迎使用! ****************************\n"); } 四、程序代码(根据前面的思想分析,算法整理得到完整的可编译可调试的程序) 源代码: #include #include typedefstructLNode//定义单循环链表中节点的结构 { intnum;//编号 intpwd;//password structLNode*next;//指向下一结点的指针 }LNode; /*构造结点*/ LNode*createNode(intm_num,intm_pwd) { LNode*p; p=(LNode*)malloc(sizeof(LNode));//生成一个结点 p->num=m_num;//把实参赋给相应的数据域 p->pwd=m_pwd; p->next=NULL;//指针域为空 returnp; } /**创建循环链表**/ voidcreateList(LNode**ppHead,intn) {/*创建单向循环链表ppHead,人数个数为n,并输入每个人的密码值,若 建立失败则生成头结点,让cur指向他,若建立成功则插入结点P,cur指 向的数据元素为p,后续为"空"的节点,再把P插入循环链表ppHead中*/ inti,m_pwd; LNode*p,*cur;//cur: 浮标指针 for(i=1;i<=n;i++) { printf("输入第%d个人的密码: ",i); scanf("%d",&m_pwd);//输入持有密码 p=createNode(i,m_pwd);//调用构造结点函数 if(*ppHead==NULL)//如果头结点为空 { *ppHead=cur=p;//生成头结点,让cur指向他 cur->next=*ppHead;//cur的指针域指向自身 } else//如果不为空,则插入结点 { p->next=cur->next; cur->next=p; cur=p;//cur指向新插入结点 } } printf("完成创建! \n");//提示链表创建完成 } /*出队处理*/ voidjose(LNode*ppHead,intm_pwd) {/*p指向要删除节点的前一个节点,ppHead指向要删除的节点,使p=ppHead,ppHead再指向要删除节点的下一个节点,使p和ppHead链接,输出p指向节点的编号和密码值,释放ppHead,如此循环,直至把所有节点都打印和删除为止! */ inti,j; LNode*p,*p_del;//定义指针变量 for(i=1;p! =ppHead;i++){ for(j=1;j p=ppHead;//p赋值为ppHead,p指向要删除结点的前一个结点 ppHead=ppHead->next;//ppHead指向下一个元素 } p->next=ppHead->next;//p结点与头结点链接 i=ppHead->pwd;//i赋值为ppHead->pwd j=ppHead->num;//j赋值为ppHead->num,j为要删除的密码值 printf("第%d个人出列,密码: %d\n",j,i); m_pwd=ppHead->pwd;//m_pwd赋值为ppHead->pwd free(ppHead);//释放头结点 ppHead=p->next;//ppHead重新赋值给p->next,即释放前的ppHead->pwd指针//删除报数结点 } i=ppHead->pwd;//i赋值为ppHead->pwd j=ppHead->num;//j赋值为ppHead->num printf("最后一个出列是%d号,密码是: %d\n",j,i); free(ppHead);//释放头结点 } voidinstruction() { printf("****************************************************************\n"); printf("约瑟夫环: \n"); printf("编号为1,2,3,4…,n的n个人按顺时针方向围坐一圈,每人持有一个密\n"); printf("码(正整数).一开始任选一个正整数作为报数的上限值m,从第一个人开始\n"); printf("按顺时针方向自1开始顺序报数,报到时停止.报m的人出列,将他的密码\n"); printf("m作为新的m值,从他在顺时针方向上的下一人开始重新从1报数,如此下去,\n"); printf("直到所有人全部出列为止.编程打印出列顺序.\n"); printf("******************************************************\n"); return0; } voidmenu(){ printf("**************************约瑟夫环*****************************\n"); printf("\n"); printf("[1]约瑟夫环问题的阐述\n"); printf("[2]按要求求解约瑟夫环\n"); printf("[0]退出\n"); printf("**************************欢迎使用! ****************************\n"); } /*主函数模块*/ intmain(){ intn,m,x; LNode*ppHead=NULL; menu(); for(;;){ printf("\n请选择要执行的操作: "); scanf("%d",&x); system("cls"); switch(x){ case1: printf("****************************************************************\n"); printf("约瑟夫环: \n"); printf("编号为1,2,3,4…,n的n个人按顺时针方向围坐一圈,每人持有一个密\n"); printf("码(正整数).一开始任选一个正整数作为报数的上限值m,从第一个人开始\n"); printf("按顺时针方向自1开始顺序报数,报到m时停止.报m的人出列,将他的密码\n"); printf("m作为新的m值,从他在顺时针方向上的下一人开始重新从1报数,如此下去,\n"); printf("直到所有人全部出列为止.编程打印出列顺序.\n"); printf("****************************************************************\n"); main(); break; case2: printf("\n请输入总人数n: "); scanf("%d",&n); printf("请输入开始上限数m: "); scanf("%d",&m); createList(&ppHead,n); printf("\n"); printf("出队顺序: \n"); jose(ppHead,m); printf("\n约瑟夫环游戏结束! \n"); main(); break; case0: exit(0); default: system("cls"); printf("\n您选择的操作有误,请重新选择...\n\n\n"); main(); } } return0; } 。 五、程序调试与测试 1.调用模块时,结点结构的调用与其他模块产生冲突,导致每一行都出现两次错误,加入子函数的声明后错误消失。 2.刚开始时曾忽略了一些变量参数的标识"&"和“*”,使调试程序时费时不少。 今后应重视确定参数的变量和赋值属性的区分和标识。 3.本次课程设计采用数据抽象的程序设计方法,将程序划分为三个层次结构: 元素节点、单向循环链表,主控制模块。 思路较为清晰,实现调用顺利。 经过本次实验,使我对数据结构这门课程有了进一步的了解,每一个程序经过需求分析、概要设计、详细设计之后,思路即清晰呈现,程序也很快就出来了,最后经过调试、运行又有新的体验。 <测试用例> 这是一个使用循环链表的经典问题。 本程序开始运行界面如下: 选择1进入约瑟夫环问题阐述。 ①选择2,输入下列数据测试: 请输入总人数n: 7 请输入开始上限数m: 20; 请依次输入每个人的密码: 3172484 出队顺序: 6147235 ②继续选择2,输入下列数据测试: 请输入总人数n: 5 请输入开始上限数m: 30 请依次输入每个人的密码: 34567 出队顺序: 53124 ③继续选择2,输入下列数据测试: 请输入总人数n: 8 请输入开始上限数m: 14 请依次输入每个人的密码: 345678910 出队顺序: 67283514 测试完成,选择0退出。 课程设计任务分工情况说明 自我完成 课程设计自我评价 我的这次数据结构课程设计的题目是: 《约瑟夫环》,通过对该题目的设计,我加深了对数据结构及存储结构的理解,进一步地理解和掌握了课本中所学的各种数据结构,尤其是对单循环链表上基本运算的实现,学会了如何把学到的知识用于解决实际问题,锻炼了自己动手的能力。 通过这次数据结构课程设计,我感受最深的就是对于循环链表的使用,可以说对循环链表有了比以前更进一步的认识,以前只是一知半解的,如果只给个题目自己根本不能把程序完整地编写出来,所以这次课程设计最大的收获就在于对循环链表有了一定的理解,包括其中的一系列操作,如建立一个循环链表,删除链表中的一个结点,增加一个结点等。 在调试程序的时候我也有所体会,虽然约瑟夫环问题不是很难,但调试的时候还是会出现很多错误,因此我们不能认为容易就不认真对待。 在以后的学习中,要能不断发现问题,提出问题,解决问题,从不足之处出发,在不断学习中提高自己。 课程设计时间虽很短暂,但其间的内容是很充实的,在其中我学习到了很多平时书本中无法学到的东西,积累了经验,锻炼了自己分析问题,解决问题的能力,并学会了如何将所学的各课知识融会,组织起来进行学习,总而言之这段时间我学到很多,受益匪浅。 自评等级 优 指导教师评定意见等级
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 课程设计 报告 约瑟夫