退圈问题.docx
- 文档编号:27934563
- 上传时间:2023-07-06
- 格式:DOCX
- 页数:19
- 大小:34.53KB
退圈问题.docx
《退圈问题.docx》由会员分享,可在线阅读,更多相关《退圈问题.docx(19页珍藏版)》请在冰豆网上搜索。
退圈问题
退圈模拟过程
摘要:
本文将n>0个人围坐一圈看成是一个单循环链表,每次报数到某个编号的人时,该人退出圈,可以模拟成从链表中删除某个节点,而剩下的人仍构成一个单循环链表。
直到所有的认读退出圈时,单循环链表就为空了。
由于在建立单循环链表时加上了一个头结点,所以把第一个人的密码拿出单独处理。
每个人都有一个密码,所以当人数较多时就可以用系统随机为他们生成密码。
模拟过程如下:
(1)创建n>0个人的圈(链表);
(2)为每个人分配密码(用户输入或随机生成);
(3)按照密码顺时针方向删除节点(按链表循环到密码个节点时就删除那个节点);
(4)重复(3)的过程直到所有人都出列为止(链表为空)。
关键词圈单循环链表节点密码链表为空
1、问题重述
设编号为1,2,…,n(n>0)个人按顺时针方向围坐一圈,每人持有一个正整数密码。
开始时任意给出一个报数上限值m,从第一个人开始顺时针方向自1起顺序报数,报到m时停止报数,报m的人出列,将他的密码作为新的m值,从他在顺时针方向上的下一个人起重新自1起顺序报数;如此下去,直到所有人全部出列为止。
要求设计一个程序模拟此过程,并给出出列人的编号序列。
2、基本要求
用单循环链表解决,当所有人都退出圈时,则链表为空,程序要给出每次出圈人的编号(按出圈顺序),还应给出每个人持有的密码(按圈中人的编号顺序给出),节点结构体中包含有编号和密码。
3、算法思想
采用单循环链表,单循环链表的每个节点是一个结构体,由于单循环链表是有序的,所以每个节点的结构体中只需包含有该节点位置的密码和下一个节点的指针。
当一个人出圈时,在链表中操作如下:
pq
…………
当报数到Ai结束时,则在单循环链表中删除Ai,让Ai的上一个节点Ai-1的指针指向Ai的下一个节点Ai-1,这样在删除Ai后又形成了一个单循环链表,如此循环下去直到单循环链表为空时就结束程序,完成模拟。
4、模块划分
ShowMenu()函数是显示完成模拟的向导界面,运行如下:
|------------------------------------------------------------------------|
|报数退圈模拟系统|
|------------------------------------------------------------------------|
|1.用户自定义输入圈中每个人的密码|
|2.系统随机生成密码(介于1-10之间)|
|3.模拟开始!
!
!
|
|4.检查圈中是否还有人!
|
|0.退出:
安全地退出本系统|
|------------------------------------------------------------------------|
voidprint(ElemType&e)函数的功能是打印出节点的信息。
voidDoMenu(charn,LinkList&L)函数的功能是将用户选择的操作具体实施到模拟的过程。
voidinitList(LinkList&L)函数的功能是初始化一个L单循环链表。
voidcreateList(LinkList&L,intn,int*MiMa,intcho);函数创建n个节点的链表L,
MiMa是接受密码的数组,根据cho的值选择是用户自己输入还是系统随机生成密码。
voidisEmpty(LinkListL)函数用来判断L单循环链表是否为空,即退圈是否完成。
voiddeleteElem(LinkList&L,intn,void(*visit)(ElemType&))函数是模拟退圈操作,并通过调用函数指针visit输出退圈节点的信息。
voidFirst(LinkList&L,intn,intpep)函数的功能是处理模拟开始时第一个节点持有的密码,由于程序中单循环链表带有头结点,所以当开始模拟时,第一个人的密码是1,则删除自己,头接点就接入到了单循环链表中,所以模拟开始时,第一个节点要单独处理。
用到First函数。
5、数据结构
ATDLinkList{
数据对象D:
D是具有相同特性的结构体,即单循环链表中的节点。
数据关系:
R1={
基本操作:
initList(&L)
操作结果:
构造一个带头结点的空单循环链表L。
createList(&L,n,*MiMa,cho)
初始条件:
空单循环链表L已经存在。
操作结果:
创建一个带n个节点的单循环链表,节点值分别为1...n,密码的生成根据cho来确定,如果cho为1,则是用户自定义每个人的密码,如果cho是2则是系统随机生成每个人的密码。
deleteElem(&L,n,visit)
初始条件:
已经创建了节点值为1..n的n个节点的单循环链表L。
操作结果:
根据密码,模拟退圈,并用visit函数输出退圈的节点值。
isEmpty(L)
初始条件:
设计的退圈已经完成,查看单循环链表L是否还存在非空节点。
}ADTLinkList
6、测试数据
(1)产生10个节点的单循环链表,密码都为1;
(2)产生10个节点,密码随机生成。
(3)产生100个节点,密码随机生成。
七、源程序
Main.cpp
#include"linklist.h"
#include"menu.h"
#include"iostream"
usingnamespacestd;
intmain()
{
chari='9';
LinkListla;//声明一个链表节点指针la
initList(la);//初始化单链表la。
ShowMenu();//调用退圈模拟向导函数。
cout<<"选择对应数字进行操作:
";
while
(1)
{
cin>>i;
system("cls");//清除屏幕
ShowMenu();
DoMenu(i,la);//根据选择的操作i,对la操作
ShowTip();//提示应选择操作的数字范围0-4。
}
}
Menu.h
#ifndefMENU_H_INCLUDED
#defineMENU_H_INCLUDED
#include"linklist.h"
voidShowMenu();//退圈模拟向导函数。
提示用户完成模拟选择的操作。
voidShowTip();
voidDoMenu(charn,LinkList&L);//根据选择的操作n,对L操作
#endif//MENU_H_INCLUDED
Menu.cpp
#include
#include"menu.h"
usingnamespacestd;
voidShowMenu()//导航界面
{
cout<<"|-----------------------------------------------------------------------|"< cout<<"|报数退圈模拟系统|"< cout<<"|-----------------------------------------------------------------------|"< cout<<"|1.用户自定义输入圈中每个人的密码|"< cout<<"|2.系统随机生成密码(介于1-10之间)|"< cout<<"|3.模拟开始! ! ! |"< cout<<"|4.检查圈中是否还有人! |"< cout<<"|0.退出: 安全地退出本系统|"< cout<<"|-----------------------------------------------------------------------|"< } voidShowTip()//提示用户完成模拟,选择操作的范围 { cout< cout<<"-------------------操作完成---------------------"< cout<<"-----------------选择0-4继续-------------------"< cout<<"请选择: "; } voidDoMenu(charn,LinkList&L)//根据用户选择的操作,对链表L进行相应的操作 {intstaticpep=0; int*MiMa; switch(n) { case'1': cout<<"请输入人数个数: "< cin>>pep; MiMa=newint[pep]; createList(L,pep,MiMa,1);/*创建有pep个节点的单循环链表L, MiMa用来储存各节点的密码,1表示用户自己输入密码*/ break; case'2': cout<<"请输入人数个数: "< cin>>pep; MiMa=newint[pep]; createList(L,pep,MiMa,2);/*创建有pep个节点的单循环链表L, MiMa用来储存各节点的密码,1表示用户自己输入密码*/ break; case'3': deleteElem(L,pep,print);//模拟退圈操作,退出pep个节点 break; case'4': isEmpty(L);//判断退圈是否完全 break; case'0': exit(0);//退出模拟 break; default: cout<<"输入错误! "; } } Linklist.h #ifndefLINKLIST_H_INCLUDED #defineLINKLIST_H_INCLUDED #include usingnamespacestd; structElem {intsec; intid; };//链表节点的编号和密码 typedefElemElemType; structLNode { ElemTypedata; LNode*next; };//定义节点 typedefLNode*LinkList;//定义节点指针。 voidprint(ElemType&e);//节点中数值输出函数。 voidinitList(LinkList&L);//链表初始化函数。 voidcreateList(LinkList&L,intn,int*MiMa,intcho);/*创建n个节点的链表L, MiMa是接受密码的数组,根据cho的值选择是用户自己输入还是系统随机生成密码。 */ voidisEmpty(LinkListL); voiddeleteElem(LinkList&L,intn,void(*visit)(ElemType&));//对链表进行退圈操作, #endif//LINKLIST_H_INCLUDED Linklist.cpp #include"linklist.h" #include"iomanip" #include voidprint(ElemType&e)//输出节点e中的id(编号) { cout< } voidinitList(LinkList&L)//初始化单链表L。 { L=newLNode; if(! L) exit (1);//存储空间分配失败 L->next=NULL;//初始化头结点为空 } voidcreateList(LinkList&L,intn,int*MiMa,intcho)/*创建n个节点的链表L, MiMa是接受密码的数组,根据cho的值选择是用户自己输入还是系统随机生成密码。 */ { ElemTypee; LinkListp; LinkListr=L; switch(cho) { case1: cout<<"请输入密码: "< for(inti=1;i<=n;++i) { p=newLNode;//动态产生一个节点 e.id=i;//节点中id的值为节点在链表中的位置 cin>>e.sec;//用户输入密码 MiMa[i]=e.sec; p->data=e; p->next=NULL; r->next=p; r=r->next; } break; case2: srand((unsigned)time(0)); for(inti=1;i<=n;++i) { p=newLNode; MiMa[i]=rand()%10+1;//系统自定义随机生成密码 e.id=i;//节点中id的值为节点在链表中的位置 e.sec=MiMa[i]; p->data=e; p->next=NULL; r->next=p; r=r->next; } break; } p->next=L->next;//尾节点指向头结点的下一节点,形成单循环链表 cout< cout<<"密码输出如下: "< for(inti=1;i<=n;i++) { cout< if(i%10==0)//满十个就换行 cout< } } voidFirst(LinkList&L,intpep)/*用来处理模拟开始时第一个节点的密码, 因为有头结点,所以当密码为1时,就把头结点加入到了循环链表中,为1时就要把加入到链表中的头结点删除*/ { inti=pep,n; LinkListp=L,q; n=p->next->data.sec;//n等于第一个节点的密码 cout< cout<<"模拟开始了: "< if(n==1) { while(p->next! =NULL&&i! =0)//找到尾节点 { i--; p=p->next; } q=p->next;//p是尾节点 cout< p->next=q->next;//将头接点排除在单循环链表之外 deleteq; } else { if(n<1)//密码小于1则退出 exit (1); i=0; while(i { p=p->next; ++i; } q=p->next; cout< p->next=q->next; deleteq; } L->next=p;//从删除的节点的下一个节点开始下一次操作 } voidisEmpty(LinkListL)//判断退圈是否完全 { if(L->next! =NULL) cout<<"圈中没有剩余了。 "< else cout<<"圈中有剩余! ! ! "< } voiddeleteElem(LinkList&L,intn,void(*visit)(ElemType&))/*对单循环链表L中的n个节点进行退圈操作 并用visit指针函数进行输出操作*/ { LinkListp=L,q; inti=0,count=2,num=n; intstaticpos=0; intw[n];//用来记录删除的节点的密码 w[1]=L->next->data.sec;//w[1]等于第一个节点的密码 First(p,n); p=p->next;//进行一次退圈删除后要从下一个节点开始操作 pos=p->data.sec;//pos等于新节点的密码 while(p->next! =NULL&&n! =1) { if(pos<1)//密码小于1则退出 exit (1); i=0; while(i { p=p->next; ++i; } q=p->next; visit(q->data);//输出退圈的编号 pos=q->data.sec;//新的密码为删除的节点密码 w[count++]=q->data.sec;//保存退圈节点的密码 p->next=q->next; deleteq; n--; if(n%10==0)//输出一行,满十个时就换行 cout< } cout< cout<<"密码输出如下: "< for(inti=1;i<=num;i++) { cout< if(i%10==0) cout< } } 8、测试情况 (1)产生10个节点的单循环链表,密码都为1,输出如下: |------------------------------------------------------------------------| |报数退圈模拟系统| |------------------------------------------------------------------------| |1.用户自定义输入圈中每个人的密码| |2.系统随机生成密码(介于1-10之间)| |3.模拟开始! ! ! | |4.检查圈中是否还有人! | |0.退出: 安全地退出本系统| |------------------------------------------------------------------------| 模拟开始了: 12345678910 密码输出如下: 1111111111 -------------------操作完成--------------------- -----------------选择0-4继续------------------- 请选择: (2)产生10个节点,密码随机生成,输出如下: |------------------------------------------------------------------------| |报数退圈模拟系统| |------------------------------------------------------------------------| |1.用户自定义输入圈中每个人的密码| |2.系统随机生成密码(介于1-10之间)| |3.模拟开始! ! ! | |4.检查圈中是否还有人! | |0.退出: 安全地退出本系统| |-----------------------------------------------------------------------| 模拟开始了: 24536781091 密码输出如下: 21711988102 -------------------操作完成--------------------- -----------------选择0-4继续------------------- 请选择: (3)产生100个节点,密码随机生成,输出如下: |------------------------------------------------------------------------| |报数退圈模拟系统| |------------------------------------------------------------------------| |1.用户自定义输入圈中每个人的密码| |2.系统随机生成密码(介于1-10之间)| |3.模拟开始! ! ! | |4.检查圈中是否还有人! | |0.退出: 安全地退出本系统| |------------------------------------------------------------------------| 模拟开始了: 413222837475059667173 7886969731417182534 36444548495664657579 859526112633525361 6883989212930435455 6970808852438516081 94100723324267849315 19416387124082922058 9927741646729091771 35397689106283157 密码输出如下: 49691039752 58101693168 2712167173 69525961016 410107741931 715510105638 9228356666 2756979467 95894341102 411017310191 -------------------操作完成--------------------- -----------------选择0-4继续------------------- 请选择: 9、心得体会 虽然程序解决的问题很简单,但我却从中学习到了很多宝贵的经验,特别是将以前学过的知识与要解决的问题相结合,当得到一个结果时,还要精益求精,包括基本操作和其他算法的时间复杂度和空间复杂度的分析,改进程序,力求完美,特别是要注意每个细节,就像本程序中,由于使用了头结点,开始没有注意,测试时只要第一个节点的密码不为1,就能得到正确结果,但要是刚好开始模拟时第一个节点的密码为1,就得不到正确的结果。 本程序由于使用了头结点,程序显得冗长,可以改进为不要头结点的但循环链表,当模拟开始时,时间复杂度和密码联系在一起,若密码都很小,则时间复杂度很小,所以时间复杂度要根据密码来得到,运算次数是密码的乘积。 10、参考文献 [1]严蔚敏数据结构(C语言版)清华大学出版社2007 [2]谭浩强C++程序
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 问题
![提示](https://static.bdocx.com/images/bang_tan.gif)