大学数据结构课程设计-实习报告——约瑟夫环
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
20XX年复习资料
大
学
复
习
资
料
专业:
班级:
科目老师:
日期:
数据结构实习报告
题目:程序求解约瑟夫环问题出列顺序
一、需求分析
1.以单项循环链表存储结构模拟约瑟夫环问题。
即编号为1、2、3…、n的n个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。
一开始任选一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1开始报数,报到m时停止报数。
报m的人出列,将他的密码作为新的m值,从他在顺时针方向下一个人开始重新从1报数,如此下去,直至所有的人全部出列为止。
按出列顺序印出各人的编号。
2.演示程序以用户与计算机的对话方式执行,用户输入相应的数据,输出结果显示在其后。
3.测试数据:
(1)n=7
7个人的密码依次为:3,1,7,2,4,8,4;
首先m值为6(正确的输出顺序为:6,1,4,7,2,3,5)
(2)n=5
5个人的密码依次为:1,2,3,4,5
首先m值为1(正确的输出顺序为:1,2,4,3,5)
(3)n=5
首先m值为-2(输入的人数和初始密码不能为负数!)
二、概要设计
为实现上述程序功能,应利用单向循环链表存储结构模拟此过程。
1.单向循环链表的抽象数据类型定义为:
ADT CircularList{
数据对象:D={ai|ai∈LNode,i=1,2,…,n,n≥0}
数据关系:R1={<ai-1,ai>|ai-1∈D,i=2,…,n}
基本操作:
Status ListDelete_L(LinkList &L,int I,ElemType &e)
操作结果:在带头结点的单链表L中,删除第i个元素,并用e返回其值}
2.本程序中包括的三个基本模块:
1)主程序模块:
Void main(){
初始化;
do{
接受命令;
处理命令;
}while(“命令”=”退出”)
}
2)线性表模块:实现线性表的抽象数据结构
3)元素结构单元模块:定义线性表中每个元素的结构
三、详细设计
1.结点类型
typedef struct LNode
{
int data;//密码
int i;//编号
struct LNode *next;
}LNode, *LinkList;
2.用循环链表存储约瑟夫环,没有头结点,基本操作函数如下:int CreateList(LinkList &L,int a[],int n)
{//创建循环链表结构的约瑟夫环
LinkList s,r;
int i;
r=L;
for(i=1;i<=n;i++)
{
s=(LinkList )malloc(sizeof(LNode));
s->data=a[i];
s->i=i;
if(i==1)
{
L=s;
s->next=s;
r=s;//尾指针指向当前元素
}
else
{
s->next=r->next;
r->next=s;
r=s;
}
}
return 1;
}
int ListDelete_L(LNode *L)
{//删除表中一个结点
if(L->next==L)//只剩一个结点
{
printf("%d\n",L->i);
free(L);
return 0;
}
LNode *p;
p=L->next;//p指向要删除元素的下一个结点
while(p->next!=L)
p=p->next;
LNode *q=L;//q指向需要被删除的元素结点
int e=L->i;
p->next=L->next;
free(q);
printf("%d ",e);
return 1;
}
int FindNode(LinkList L,int x)
{//查找表中某个结点
LinkList p=L;
LinkList q;
for(int i=1;i<x;i++)
p=p->next;
q=p->next;//下一次循环的起始位置
x=p->data;
if(ListDelete_L(p))
FindNode(q,x);
return p->i;
}
3.主函数:
int main()
{
int n,m;
LinkList L;
printf("请输入人数和初始密码:");
scanf("%d %d",&n,&m);
if(n<0||m<0)
{
printf("输入的人数和初始密码不能为负数!\n");
return 0;
}
int a[20XXXX0];
printf("请输入每个人的密码:");
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
if(CreateList(L,a,n))
{
printf("\n");
printf("正确的出列顺序为:");
FindNode(L,m);
printf("\n");
}
return 0;
}
4.函数的调用关系图反映了演示程序的层次结构:
CreateList FindNode
ListDelete_L
四、调试分析
1.刚开始时,忽略了题目要求的没有头结点这一项,没有把第一个结点单独拿出来建立,出现了逻辑上的错误。
2.程序在编译时,有很多错误,主要是指针与引用概念不清导致。
3.查找下一个时候采用求余数的方法,减少了循环次数。
4.程序的算法复杂度为O(n2),不过虽然是C++写的,但还有很大的面向过程的思想,函数间的调用显得不好。
五、用户手册
1.本程序的运行环境为DOS操作系统,执行文件名为:JosephC.exe
2.运行程序后,需要根据提示输入人数n、初始密码m,然后根据提示输入 n 个正整数,作为这n个人的密码,密码之间用空格隔开。
3.按回车键即可得到测试结果。
4.本程序的输入输出只进行一次,即只做一个案例的处理,如果用户要输入第二个案例,则需要退出并再运行本程序。
六、测试结果
1.第一组数据测试结果:
请输入人数和初始密码:7 20XX
请输入每个人的密码:3 1 7 2 4 8 4
正确的出列顺序为:6 1 4 7 2 3 5
2.第二组数据测试结果:
请输入人数和初始密码:5 1
请输入每个人的密码:1 2 3 4 5
正确的出列顺序为:1 2 4 3 5
3.第三组数据测试结果:
请输入人数和初始密码:5 -2
输入的人数和初始密码不能为负数!。