数据结构实验一josephWord文件下载.docx
《数据结构实验一josephWord文件下载.docx》由会员分享,可在线阅读,更多相关《数据结构实验一josephWord文件下载.docx(14页珍藏版)》请在冰豆网上搜索。
八、主要参考资料11
一、设计任务与要求
1.1总体目标与任务要求
总体目标:
用C++软件设计一个程序用来求出一个序列的出列顺序。
要求:
利用单向循环链表存储结构实现这个过程,按照出列的顺序输出每一个人的编号。
1.2题目选择与目的意义
据说joseph在战争时期,与39个犹太人和他一个朋友躲到一个洞里,39个犹太人决定宁死也不被敌人抓到,于是他们决定了一个自杀方式,41个人排成圈,由第一个人开始报数,每报到三的人就必须自杀,依次循环直到每个人都自杀身亡。
但josrph和他的朋友并不想村从,于是他把自己和朋友安排到第16个位置和第31个位置,于是他们俩逃过了这个死亡游戏。
Joseph问题是个很由意思的问题,其意义在于它启发我们用一个循环的链来表示这个圈子,可以使用结构数组来构成一个循环链。
结构中有两个成员,其一为指向下一个人的指针,以构成环形的链;
其二为该人的标记。
所以我们选择了这个题目。
1.3所选题目的主要工作
以单向循环链表的方式建立约瑟夫环。
建立输入处理输入数据,输入m的初值,n,建立单向链表,输入每个人的密码建立一个输出函数,将正确的出列顺序输出序列。
二、需求分析
2.1用户需求分析
编号是1,2,……,n的n个人按照顺时针方向围坐一圈,每个人只有一个密码(正整数)。
一开始任选一个正整数作为报数上限值m,从第一个仍开始顺时针方向自1开始顺序报数,报到m时停止报数。
报m的人出列,将他的密码作为新的m值,从他在顺时针方向的下一个人开始重新从1报数,如此下去,直到所有人全部出列为止。
设计一个程序来求出出列顺序。
2.2功能需求分析
各个模块间的调用关系如下:
2.3系统需求分析
系统软件:
Windows操作系统
开发软件:
MicrosoftVisualC++6.0
其他软件:
MicrosoftOfficeWord2003,AdobePhotoshopCS3
三、概要设计
3.1各模块的算法设计说明
函数流程图:
joseph*creat(void),voidgame(joseph*head,intm),voidmain()部分函数流程图:
3.2存储结构设计说明
typedefstructNode
{
ElemTypedate;
//编号
intmima;
//密码
structNode*next;
}Node,*LinkList;
单向循环链表:
LinkListH;
//表头指针
Node*Q,*Pre;
//*Q指新建结点,*pre指向当前工作结点
Q=(Node*)malloc(sizeof(Node));
构造函数:
voidInitList(LinkList*H);
//初始化循环链表
voidInPut(LinkListH,int*A);
//插入结点
voidDelList(LinkListH,int*x,int*a);
//删除结点
四、详细设计
typedefstructLnode{//节点类型
ElemTypedata;
StructLnode*next;
}*Link,*Position;
typedefstruct{//链表类型
Linkhead,tail;
//分别指向线性链表中的头结点和最后一个结点
Intlen;
//只是线性链表中的数据元素
}LinkList;
StatusMakeNode(Link&
p,ElemTypee);
//分配由p指向的值为e的结点,并返回OK;
若分配失败,则返回ERROR
voidFreeNode(Link&
p);
//释放p所指接点
StatusInitList(LinkList&
L);
//构造一个空的线性表L
StatusDestroyList(LinkList&
//销毁线性表L,L不再存在
StatusClearList(LinkList&
//将线性表L从之唯恐表,并释放原链表的结点空间
StatusInsFirst(Linkh,Links);
//已知h指向线性链表的头结点,将s所直接点插入在第一个结点之前
StatusDelFirst(Linkh,Link&
q);
//已知h指向线性表的头结点,删除链表中的第一个结点并以q返回
StatusAppend(LinkList&
L,Links);
//将指针s所指(彼此以指针项链)的一串结点链接在线性链表L的最后一个结点
//之后,并改变链表L的尾指针指向新的尾节点
StatusRemove(LinkList&
L,Link&
//删除线性链表L中的尾结点并以q返回,改变链表L的尾指针只想新的尾结点
StatusInsBefore(LinkLIst&
p,Links);
//已知p指向线性链表L中的一个结点,将s所指结点插入在p所指结点之前,
//并修改指针p指向新插入的结点
StatusInsAfter(LinkLIst&
//已知p指向线性链表L中的一个结点,将s所指结点插入在p所指结点之后,
StatusSetCurElem(Link&
//已知p指向线性链表中的一个结点,用e更新p所指结点中的数据元素的值
ElemTypeGetCurElem(Linkp);
//已知p指向线性链表中的一个结点,返回p所指结点中数据元素的值
StatuslistEmpty(LinkListL);
//若线性链表L为空表,则返回TRUE,否则返回FALSE
intListLength(LinkListL);
//返回线性链表L中元素个数
PositionGetHead(LinkListL);
//返回线性链表L中头结点的位置
PositionGetLast(LinkListL);
//返回线性链表L中最后一个结点的位置
PositionPriorPos(LinkListL,Linkp);
//已知p指向线性链表L中的一个结点,返回p所指结点的直接前驱的位置‘
//若无前驱,则返回NULL
PositionNextPos(LinkListL,Linkp);
//已知p指向线性链表L中的一个结点,返回p所指结点的直接后继的位置‘
//若无后继,则返回NULL
StatusLocatePos(LinkListL,intI,Link&
//返回p指示线性链表L中的第I个节点的位置并返回OK,i值不合法时返回ERROR
PositionLocateElem(LinkListL,ElemTypee,Status(*compare)(ElemType,ElemType));
//返回线性链表L中的第1个与e满足函数compare()判定关系的元素的位置,
//若不存在这样的元素,则返回NULL
StatusListTraverse(LinkListL,status(*visit)());
//依次对L的每个元素调用函数visit()。
一旦visit()失败,则操作失败
五、源代码
#include<
iostream.h>
stdio.h>
malloc.h>
stdlib.h>
#include<
conio.h>
typedefstructajose
{
intnum;
intcode;
}joseph;
structajose*next;
joseph*creat(void)
joseph*head,*p1,*p2;
inti=0,code;
head=(joseph*)malloc(sizeof(joseph));
p2=p1=(joseph*)malloc(sizeof(joseph));
head->
next=NULL;
cout<
<
"
请输入第"
i+1<
个人的密码(输入0结束输入):
endl;
scanf("
%d"
&
code);
while(code)
{
i++;
p1=(joseph*)malloc(sizeof(joseph));
p1->
num=i;
code=code;
if(i==1)
head->
next=p1;
else
p2->
p2=p1;
cout<
scanf("
}
p2->
next=head->
next;
printf("
建立成功!
~\n"
);
returnhead;
}
voidgame(joseph*head,intm)
joseph*p1,*p2;
inti=1;
p2=head;
p1=head->
while(head->
num>
1)
if(i==m)
{
next=p1->
m=p1->
code;
i=1;
printf("
%3d"
p1->
num);
free(p1);
p1=p2->
//p1指向输出结点
num--;
continue;
}
i++;
p2=p1;
p1=p1->
//将p1指针指向所要输出的结点的前一结点
}
return;
voidmain()
joseph*head;
intm;
head=creat();
printf("
请输入m的值m:
m);
game(head,m);
getch();
\njoseph环单向循环链表结束\n"
}
六、运行结果分析
由于刚开始忽略了该链表没有头结点这样一个特殊性,没有把第一个结点单独拿出来建立,因而出现了一些逻辑上的错误
程序写完后发现所有基本操作的结果均不能够返回到主函数,后通过XX百科和以前的C教材知道要用传址的方式调用,但是具体实现起来还是耗费了不少的时间
算法的时空分析
该程序不占用额外空间,因此空间复杂度是O(n)的,基本操作中,Destroy操作是O(n)的,Next_m操作是O(m)的,其余的操作都是O
(1)的,整个程序的时间复杂度是O(n*m)的
七、收获与体会
通过学习和实践,使我明白在进行面向过程的程序设计时,一般首先考虑程序所要实现的功能,然后设计为实现这些功能所必须采取的步骤,这些步骤就是过程。
如果一个过程比较复杂而不能直接使用已有的抽象进行实现,则对这个过程进行分解,使分解之后的每一步(更低级的过程)能够直接对应着一条语句。
通过将分解之后的一系列过程封装在一个函数抽象中,程序员在特定的时刻只关心有限的细节,这个新的函数抽象比其较低级的抽象更接近问题求解的过程,因而,能够很好地映射问题求解中的过程。
如果这个过程出现在许多问题求解中,那么,这个函数抽象就可能被重复利用。
由于是第一次用“以数据结构为中心”的思想编程,所以并不是很习惯,在主函数中还是充斥着很多基本语句,以后仍要多多练习。
八、主要参考资料
[1]JamesP.Cohoon&
JackW.Davidson.《C++程序设计》.电子工业出版社
[2]严蔚敏.《数据结构(C语言版)》.清华大学出版社
[3]姚云鸿.《程序设计与数据结构》.清华大学出版社
指导教师签字:
年月日
#include<
iostream>
usingnamespacestd;
typedefstructCirList
{
intnum,pwd;
structCirList*next;
}CirList,*LCirList;
intmain()
intm,n;
//max为报数上限,num为人数。
inti,j;
Pleaseentern="
n);
Pleaseenterm="
LCirListhead,tail,p,q;
//head为头节点指针,tail为尾节点指针,p为当前指针的前一指针,q为当前指针。
head=(CirList*)malloc(sizeof(CirList));
p=head;
for(i=1;
i<
n;
i++)
q=(CirList*)malloc(sizeof(CirList));
p->
next=q;
p=q;
tail=q;
tail->
next=head;
//建立num个节点的循环链表。
=n;
num=i;
PleaseenterNo.%d'
spassword:
i);
(p->
pwd));
p=p->
}//输入密码。
result:
p=tail;
for(i=1;
=n;
for(j=1;
j<
m;
j++)
q=p->
m=q->
pwd;
%d"
q->
next=q->
//删除元素
free(q);
}//输出编号。
return0;
}