约瑟夫环 c语言版 课程设计
C语言用循环单链表实现约瑟夫环
C语⾔⽤循环单链表实现约瑟夫环⽤循环单链表实现约瑟夫环(c语⾔),供⼤家参考,具体内容如下源代码如下,采⽤Dev编译通过,成功运⾏,默认数到三出局。
主函数:main.c⽂件#include <stdio.h>#include "head.h"#include "1.h"int main(){Linklist L;int n;printf("请输⼊约瑟夫环中的⼈数:");scanf("%d",&n);Createlist(L,n);printf("创建的约瑟夫环为:\n");Listtrave(L,n);printf("依次出局的结果为:\n");Solution(L,n);return 0;}head.h⽂件:#include "1.h"#include <stdio.h>#include <stdlib.h>typedef int Elemtype;typedef struct LNode{Elemtype data;struct LNode *next;}LNode,*Linklist;void Createlist(Linklist &L,int n){Linklist p,tail;L = (Linklist)malloc(sizeof(LNode));L->next = L;//先使其循环p = L;p->data = 1;//创建⾸节点之后就先给⾸节点赋值,使得后⾯节点赋值的操作能够循环tail = L;for(int i = 2;i <= n;i++){p = (Linklist)malloc(sizeof(LNode));p->data = i;p->next = L;tail->next = p;tail = p;}printf("已⽣成⼀个长度为%d的约瑟夫环!\n",n);}void Listtrave(Linklist L,int n)//遍历函数{Linklist p;p = L;for(int i = 1;i <= n;i++){printf("%3d",p->data);p = p->next;}printf("\n");}int Solution(Linklist L,int n){Linklist p,s;p = L,s = L;int count = 1;while(L){if(count != 3){count++;p = p->next;//进⾏不等于3时的移位}else{Linklist q;q = p;//⽤q保存p所指的位置,⽅便进⾏节点的删除if(s->next->data == s->data)//当只有⼀个元素的时候{printf("%3d\n",s->data);free(s);return OK;}else//当有两个及两个以上的元素的时候{count = 1;//先将count重置为1printf("%3d",p->data);//再打印出出局的值while(s->next != p){s = s->next;//将s移位到p的前驱节点处}p = p->next;//使p指向⾃⼰的下⼀个节点s->next = p;//进⾏删除free(q);}}}}1.h⽂件:#define TRUE 1#define FALSE 0#define OK 1#define ERROR 0#define INFEASIBLE -1#define OVERFLOW -2运⾏结果:以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。
约瑟夫问题面向对象(C++版)程序设计报告
函数
相关说明
Jose(int boys, int interval, int begin=1);
构造函数,主要功能初始化各个参数,校验输出的m、n、s参数为int boys, int interval, int begin=1
void getWinner()const;
//构造函数
//-------------------------------------
BoyRing::BoyRing(int n)
{
if(n<2) throw exception(); //发生错误时自动跳出
pBegin = new Boy[n]; //申请一个新的Boy空间,pBegin指向该空间的开始处
for(int i=1; i<=n; i++)
{
pBegin[i-1].next = &pBegin[i%n];//形成链表
pBegin[i-1].code = i;//给孩子孩子编号
}
pivot = pCurrent = &pBegin[n-1];//各指针初始化
}
//------------------------------------
2详细设计
2.1程序结构
改程序分成三个抽象层次,第一层是应用层,直接指使Jose类对象去完成求解工作;第二层是Jose类层,描述Josephus问题的求解细节;第三层是BoyRing类层,辅助Jose类完成求解过程(上述三层间的关系描述如图J-1,这也是程序模块间的关系)。
图J-1.对象实现中程序模块的相互关系
void disengage();
利用指针实现小孩离队,无参数
实验报告——约瑟夫环
《数据结构》课程设计报告课程名称:《数据结构》课程设计课程设计题目:约瑟夫环姓名:张光栋院系:计算机学院专业:网络工程年级:2013级学号:13055532指导教师:张纪林一、需求分析1.以单项循环链表存储结构模拟约瑟夫环问题。
即编号为1、2、3…、n的n 个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。
一开始任选一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1开始报数,报到m时停止报数。
报m的人出列,将他的密码作为新的m值,从他在顺时针方向下一个人开始重新从1报数,如此下去,直至所有的人全部出列为止。
按出列顺序印出各人的编号。
2.演示程序以用户与计算机的对话方式执行,用户输入相应的数据,输出结果显示在其后。
3.测试数据:(1)n=55个人的密码依次为:2,4,2,6,2;首先m值为2(正确的输出顺序为:2 1 4 3 5)(2)n=77个人的密码依次为:2,4,1,4,3,2,3首先m值为5(正确的输出顺序为:5 1 3 4 6 2 7)二、概要设计为实现上述程序功能,可利用单向循环链表存储结构模拟此过程。
1.单向循环链表的抽象数据类型定义为:ADT CircularList{数据对象:D={ai|ai∈LNode,i=1,2,…,n,n≥0}数据关系:R1={<ai-1,ai>|ai-1∈D,i=2,…,n}基本操作:Status LisCreate_L(LinkList &L,int I,ElemType &e)操作结果:在不带头结点的单链表L中,创建第i个元素,并用e赋值}2.本程序中包括的两个基本模块:1)主程序模块:Void main(){初始化;do{接受命令;处理命令;}while(“命令”=”退出”)}2)循环链表模块:实现循环链表的抽象数据结构三、详细设计1.结点类型typedef struct ListNode{int mi;int n;struct ListNode *next;}ListNode,*LinkList;2.用循环链表存储约瑟夫环,没有头结点,基本操作函数如下:void CreateList(LinkList&L, int n){LinkList s;int i;L=(LinkList)malloc(sizeof(ListNode));L->n=1;L->next=L;for(i=2;i<=n;i++){s=(LinkList)malloc(sizeof(ListNode));s->next=L->next;L->next=s;s->n=i;L=L->next;}}void Delete(LinkList L, int m){int i;LinkList p,q;p=L;while(p->next!=p){for(i=1;i<m;i++)p=p->next;q=p->next;m=q->mi;printf("%d ",q->n);p->next=q->next;free(q);}printf("%d ",p->n);free(p);}3.主函数:int main(){int n,i,m;LinkList L,p;printf("请输入人数:");scanf("%d",&n);CreateList(L,n);printf("请输入密令\n");p=L->next;for(i=1;i<=n;i++){printf("请输入第%d条密令\n",i);scanf("%d",&p->mi);p=p->next;}printf("请输入初始密令\n");scanf("%d",&m);printf("输出为\n");Delete(L, m);return 0;}四、调试分析1.第一次写时,没有区分出只剩下的一个的情况,导致最终输出出现错误。
模板约瑟夫环(Joseph)问题.ppt
最新 文档
10
4.详细设计
main()函数
Joseph()函数
从循环链表中按初始密码 依次找出对应出列序列
输出每个人持有的密码c
所有密码c输出后,删除相应 的节点,并释放所占的存储
空间
图5 输出序列的实现
最新 文档
11
5.测试报告
//尾插入法创建链表
void CreateLinkList(LinkList *&L,int n)
最新 文档
3
2.问题描述
编号是1,2,……,n的n个人按照顺时针方向围 坐一圈,每个人只有一个密码(正整数)。一 开始任选一个正整数作为报数上限值m,从第一 个人开始顺时针方向自1开始顺序报数,报到m 时停止报数。报m的人出列,将他的密码作为 新的m值,从他在顺时针方向的下一个人开始 重新从1报数,如此下去,直到所有人全部出 列为止。设计一个程序来求出出列顺序。
int i = 1;
c = L;
printf("输出出对序列:");
while (n)
{
while (i != m)
{
s = c;
c = c->next;
i++;
}
printf("%-3d",c->data);
m = c->cipher;
s->next = c->next;
free(c);
c = s->next;
8 这就是第三步的位置, 这时他的密码作为新的 m值,即m=9,同时得 到的第二个密码为9;9 号出去向下走9,到这 儿;继续走就行了(这 儿剩余的就是:1,2,
3,5,6,7,8,9)
数据结构约瑟夫环问题
数据结构实验报告题目:约瑟夫环问题一.设计内容[问题描述]约瑟夫环问题的一种描述是:编号为1, 2, 3,…,n的n个人按顺时针方向围坐一圈,每人手持一个密码(正整数)。
一开始任选一个整数作为报数上限值,从第一人开始顺时针自 1 开始顺序报数,报到m 时停止报数。
报m 的人出列, 将它的密码作为新的m 值,从他在顺时针方向上的下一个人开始重新从 1 报数, 如此下去直到所有人全部出列为止。
试设计程序实现之。
[基本要求] 利用循环链表存储结构模拟此过程,按照出列的顺序打印各人的编号。
[ 实验提示] 程序运行后首先要求用户指定初始报数上限值。
然后读取各人的密码。
设n<=30 。
程序执行后,要求用户在计算机终端上显示“提示信息”后,用键盘输入“提示信息”中规定的命令,以“回车符”为结束标志。
相应的输入数据和运算结果显示在其后。
二、设计目的1. 达到熟练掌握C++ 语言的基本知识和技能;2. 能够利用所学的基本知识和技能,解决简单的面向对象程序设计问题。
3. 把课本上的知识应用到实际生活中,达到学以致用的目的。
三、系统分析与设计(确定程序功能模块)1、为实现上述程序的功能,应以有序链表表示集合。
基本操作:InitList(&L)操作结果:构造一个空的有序表L。
DestroyList(&L)初始条件:有序表L 已存在。
操作结果:销毁有序表L。
ListEmpty(L)初始条件:有序表L 已存在。
操作结果:若L为空表,则返回TRUE,否则返回FALSE。
ListLength(L)初始条件:有序表L 已存在。
操作结果:返回L 中数据元素个数。
GetElem(L,i)初始条件:有序表L已存在,并且K i< ListLength(L)。
操作结果:返回L 中第i 个数据元素。
LocatePos(L,e)初始条件:有序表L已存在,e和有序表中元素同类型的值。
操作结果:若L中存在和e相同的元素,则返回位置;否则返回0。
C语言的循环链表和约瑟夫环
C语言的循环链表和约瑟夫环C语言的循环链表和约瑟夫环约瑟夫问题)是一个数学的应用问题,对于学习C语言四非常挺有帮助的,下面是店铺为大家搜集整理出来的有关于C语言的循环链表和约瑟夫环,一起了解下吧!循环链表的实现单链表只有向后结点,当单链表的尾链表不指向NULL,而是指向头结点时候,形成了一个环,成为单循环链表,简称循环链表。
当它是空表,向后结点就只想了自己,这也是它与单链表的主要差异,判断node->next是否等于head。
代码实现分为四部分:1. 初始化2. 插入3. 删除4. 定位寻找代码实现:1 2 3 4 5 6 7 8 9 1 0 1 1 1 2 1 3 1void ListInit(Node *pNode){int item;Node *temp,*target;cout<<"输入0完成初始化"<<endl; cin="">>item;if(!item)return ;if(!(pNode)){ //当空表的时候,head==NULLpNode = new Node ;if(!(pNode))exit(0);//未成功申请pNode->data = item;pNode->next = pNode;}else{//for(target = pNode;target->next!=pNode;target = target->next);4 15 16 17 18 19 2 0 2 1 2 2 2 3 2 4 2 5 2 6 2 7 2 8 2 9 3 0 3 1 3 2 3 3 3 4 3 5 3temp = new Node;if(!(temp))exit(0);temp->data = item;temp->next = pNode;target->next = temp;}}}void ListInsert(Node *pNode,int i){ //参数是首节点和插入位置Node *temp;Node *target;int item;cout<<"输入您要插入的值:"<<endl; cin="">>item;if(i==1){temp = new Node;if(!temp)exit(0);temp->data = item;for(target=pNode;target->next != pNode;target = target->next);temp->next = pNode;target->next = temp;pNode = temp;}else{target = pNode;for (int j=1;j<i-1;++j) target="target-">next;temp = new Node;if(!temp)exit(0);temp->data = item;temp->next = target->next;target->next = temp;}}void ListDelete(Node *pNode,int i){Node *target,*temp;if(i==1){for(target=pNode;target->next!=pNode;target=target ->next);temp = pNode;//保存一下要删除的首节点 ,一会便于释放6 37 38 39 4 0 4 1 4 2 4 3 4 4 4 5 4 6 4 7 4 8 4 9 5 0 5 1 5 2 5 3 5 4 5 5 5 6 5 7 5pNode = pNode->next;target->next = pNode;temp;}else{target = pNode;for(int j=1;j<i-1;++j) target="target-">next;temp = target->next;//要释放的nodetarget->next = target->next->next;temp;}}int ListSearch(Node *pNode,int elem){ //查询并返回结点所在的位置Node *target;int i=1;for(target = pNode;target->data!=elem && target->next!= pNode;++i)target = target->next;if(target->next == pNode && target->data!=elem)return 0;else return i;}</i-1;++j)></i-1;++j)></endl;></endl;>5 96 0 6 1 6 2 6 3 6 4 6 5 6 6 67 68 69 7 0 7 1 7 2 7 3 7 4 7 5 7 6 7 7 7 8 7 9 8约瑟夫问题约瑟夫环(约瑟夫问题)是一个数学的'应用问题:已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。
约瑟夫问题详解(CC++)
约瑟夫问题详解(CC++)Josephus 约瑟夫问题假设n个竞赛者排成一个环形,依次顺序编号1,2,…,n。
从某个指定的第1号开始,沿环计数,每数到第m个人就让其出列,且从下一个人开始重新计数,继续进行下去。
这个过程一直进行到所有的人都出列为止。
最后出列者为优胜者。
无论是用链表实现还是用数组实现来解约瑟夫问题都有一个共同点:要模拟整个游戏过程,不仅程序写起来比较麻烦,而且时间复杂度高达O(nm),当n,m非常大(例如上百万,上千万)的时候,几乎是没有办法在短时间内出结果的。
注意到原问题仅仅是要求出最后的胜利者的序号,而不是要模拟整个过程。
因此如果要追求效率,就要打破常规,实施一点数学策略。
为了讨论方便,先把问题稍微改变一下,并不影响原意:问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数。
求胜利者的编号。
我们知道第一个人(编号一定是m%n-1) 出列之后,剩下的n-1个人组成了一个新的约瑟夫环(以编号为k=m%n的人开始): k k+1 k+2 ... n-2, n-1, 0, 1, 2, ... k-2并且从k开始报0。
现在我们把他们的编号做一下转换:k --> 0k+1 --> 1k+2 --> 2......k-2 --> n-2变换后就完完全全成为了(n-1)个人报数的子问题,假如我们知道这个子问题的解:例如x 是最终的胜利者,那么根据上面这个表把这个x变回去不刚好就是n个人情况的解吗?变回去的公式很简单:x'=(x+k)%n如何知道(n-1)个人报数的问题的解?显然,只要知道(n-2)个人的解就行了。
(n-2)个人的解呢?当然是先求(n-3)的情况---- 这显然就是一个倒推问题!递推公式:令f[i]表示i个人玩游戏报m退出最后胜利者的编号,最后的结果自然是f[n]递推公式f[1]=0;f[i]=(f[i-1]+m)%i; (i>1)有了这个公式,我们要做的就是从1-n顺序算出f[i]的数值,最后结果是f[n]。
顺序表实现约瑟夫环的问题,C语言
顺序表实现约瑟夫环的问题,C语言计算机科学与工程学院《算法与数据结构》试验报告[一] 专业班级 10级计算机工程02 试验地点计算机大楼计工教研室学生学号 1005080222 指导教师蔡琼学生姓名肖宇博试验时间 2012-2-29试验项目算法与数据结构试验类别基础性() 设计性() 综合性(?) 其它( )(1)掌握用VC++上机调试线性表的基本方法; 试(2)掌握顺序表的存储结构以及基本运算的实现。
验目的及要求成绩评定表类别评分标准分值得分合计积极出勤、遵守纪律上机表现 30分主动完成设计任务程序代码规范、功能正确程序与报告 70分报告详实完整、体现收获备注:评阅教师:日期: 年月日计算机科学与工程学院试验内容一、实验目的和要求1、实验目的:(1)掌握用VC++上机调试线性表的基本方法;(2)掌握顺序表的存储结构以及基本运算的实现。
2、实验内容约瑟夫环问题:设编号为1,2,3,……,n的n(n>0)个人按顺时针方向围坐一圈,m为任意一个正整数。
从第一个人开始顺时针方向自1起顺序报数,报到m时停止并且报m的人出列,再从他的下一个人开始重新从1报数,报到m时停止并且报m的人出列。
如此下去,直到所有人全部出列为止。
要求设计一个程序模拟此过程,对任意给定的m和n,求出出列编号序列。
3、实验要求:用顺序表实现。
二、设计分析根据实验要求,采用顺序表来完成本次实验。
实验中定义了两个顺序表,一个用来存储n个人的序号,另一个用来存储n个人的出队顺序及序号。
程序中充分考虑了如果出队的元素大于队列的元素个数时应该有的情况,如果出现这样的错误就提示~否则继续出队~三、源程序代码#include<stdio.h>#include<stdlib.h>#define MAXSIZE 10 // 宏替换最大值typedef struct{int data[MAXSIZE];int length;}Sqlist;void CreatList(Sqlist *&L,int a[],int n) //创建顺序表{L=(Sqlist *)malloc(sizeof(Sqlist));for(int i=0;i<n;i++){L->data[i]=a[i];}L->length=n;}void InitList(Sqlist *&L) //初始化顺序表{2 《算法与数据结构》试验报告计算机科学与工程学院L=(Sqlist *)malloc(sizeof(Sqlist));L->length=0;}void DestoryList(Sqlist *&L) //释放顺序表空间{free(L);}void josephus(Sqlist *&L) //约瑟夫环的核心代码{int t=0;int m=0;printf("请输入数到几个人出来");printf("\n");scanf("%d",&m);if(m>L->length){printf("没有这么多人呀~?(?_?)?");}else{printf("出列顺序为:");for(int q=L->length;q>=1;q--){t=(t+m-1)%q;printf("\n");printf("\t%d\t",L->data[t]);for(int j=t+1;j<=q-1;j++)L->data[j-1]=L->data[j];}printf("\n");}}void main(){Sqlist *s;InitList(s);int a[MAXSIZE];int n=0;printf("请键入要输入几个数"); printf("\n");scanf("%d",&n);for(int i=0;i<n;i++)3 《算法与数据结构》试验报告计算机科学与工程学院{a[i]=i+1;}CreatList(s,a,n);josephus(s);DestoryList(s);printf("\n");}四、测试用例(尽量覆盖所有分支) 1.当输入1,2,3,4。
循环队列之约瑟夫环问题
循环队列之约瑟夫环问题约瑟夫问题 约瑟夫环(约瑟夫问题)是⼀个数学的应⽤问题:已知n个⼈(以编号1,2,3...n分别表⽰)围坐在⼀张圆桌周围。
从编号为k的⼈开始报数,数到m的那个⼈出列;他的下⼀个⼈⼜从1开始报数,数到m的那个⼈⼜出列;依此规律重复下去,直到圆桌周围的⼈全部出列。
通常解决这类问题时我们把编号从0~n-1,最后结果+1即为原问题的解。
循环队列求解(链式)#include<stdio.h>#include<stdlib.h>//循环队列//typedef int ElemType;typedef struct QueueNode{int data;struct QueueNode *next;}QueueNode;typedef struct Queue{QueueNode *front;QueueNode *rear;}Queue;void InitQueue(Queue *q){q->front=q->rear=NULL;}void EnQueue(Queue *q , int value){QueueNode *temp=(QueueNode*)malloc(sizeof(QueueNode));temp->data=value;if(q->rear==NULL){temp->next=temp;q->rear=q->front=temp;}else{temp->next=q->rear->next;q->rear->next=temp;q->rear=temp;}}//enter a element from the tailvoid DeQueue(Queue *q, int *value){QueueNode *temp=(QueueNode*)malloc(sizeof(QueueNode)); if(q->rear==NULL){return;}// It's nullelse if(q->rear->next==q->rear){*value=q->front->data;free(q->rear);q->rear=q->front=NULL;}//It just has one nodeelse{*value=q->front->data;temp=q->front;q->front=temp->next;q->rear->next=q->front;}//more one nodefree(temp);}//delete a element from the headint main(){Queue *q=(Queue*)malloc(sizeof(Queue));int i,m,n,count,temp;printf("请输⼊⼈数n和循环要报的数m(两数之间留个空格)\n"); scanf("%d%d",&n,&m);for(i=1;i<=n;i++)EnQueue(q,i);printf("出圈序列:\n");while(q->front){ count=1;while(count<m){q->front=q->front->next;q->rear=q->rear->next;count++;}count=1;DeQueue(q,&temp);printf("%d ",temp);}putchar('\n');}简单解法#include <stdio.h>int josephus(int n, int m) {if(n == 1) {return0;}else {return (josephus(n-1, m) + m) % n;}}int main() {int n, m;while (scanf("%d", &n) == 1) {if (!n) {break;}scanf("%d", &m);int result = josephus(n, m);printf("%d\n", result+1);}return0;}。
约瑟夫环问题实验报告
//报数为m的人出列
while(n--)
{
for(int s=m-1; s--; r=p, p = p->link);
cout << "The output is: " << p->data << endl;
r->link = p->link;
LinkList d = new LNode;
if(!d)
二、实验问题描述
设编号为1,2,···,n的n个人围坐一圈,约定编号为k(1≤k≤n)的人从1开始报数,数到m的那个人出列,他的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
3、实验步骤
1、实验问题分析
①由于当某个人退出圆圈后,报数的工作要从下一个人开始继续,剩下的人仍要是围成一个圆圈,可以使用循环表;由于退出圆圈的工作对应着表中结点的删除操作,对于这种删除操作频繁的情况,应该选用效率较高的链表结构;为了程序指针每一次都指向一个具体的代表一个人的结点而不需要进行判断,链表不带表头结点。所以,对于所有人围成的圆圈所对对应的数据结构采用一个不带头结点的循环链表来描述。设头指针为p,并根据具体情况移动
可以采用数据类型定义: Typedef struct node {
int number;
struct node *next; }Lnode,*Linklist;
②为了记录退出的人的先后顺序,采用一个顺序表进行存储,程序结束后再输入依次退出的人的编号顺序。由于只记录各个结点的number值就可以,所以定义一个整型一维数组。如“int quite[N];”N为一个根据实际问题定义的一个足够大的整数。
C语言程序设计漫谈之从“约瑟夫问题”谈起
从“约瑟夫问题”谈起约瑟夫问题是一个出现在计算机科学和数学中的问题。
在计算机编程的算法中,类似问题又称为约瑟夫环。
据说著名犹太历史学家Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。
然而Josephus 和他的朋友并不想自杀。
为避免与其他39个决定自杀的犹太人发生冲突,Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
17世纪的法国数学家加斯帕在《数目的游戏问题》中讲了这样一个故事:15个教徒和15 个非教徒在深海上遇险,必须将一半的人投入海中,其余的人才能幸免于难,于是想了一个办法:30个人围成一圆圈,从第一个人开始依次报数,每数到第九个人就将他扔入大海,如此循环进行,直到仅余15个人为止。
问怎样的排法,才能使每次投入大海的都是非教徒。
【例1】约瑟夫问题。
N个人围成一圈,从某个人开始,按顺时针方向从1开始依次编号。
从编号为1的人开始顺时针“1,2,…M”报数,报到M的人退出圈子。
这样不断循环下去,圈子里的人将不断减少。
由于人的个数是有限的,因此最终会剩下一个人,该人就是优胜者。
输入N和M,输出出圈顺序。
例如,N=6、M=5,出圈的顺序是:5,4,6,2,3,1。
(1)编程思路。
为输出出圈顺序,采用一个数组来进行模拟。
定义int circle[N+1],并按circle[i]=i+1的方式赋予各元素初值。
该值代表两个含义:1)值为0,代表编号i+1的人不再圈中;2)值非0,代表圈中第i个位置的人编号为i+1。
定义变量i代表报数位置的流动,i的初值为0,代表编号为1的人的位置,i的变化方式为:i=(i+1)%(n),即0-->1-->2……->n-1 ->0-->1……。
约瑟夫环的C语言数组的实现
1 约瑟 夫 环 的 实现
针 对 很 多 以 指 针方 式 求 解 , 们 使 用数 组 来 实 现 约 瑟 夫 环 问 题 的 我 求解 。 试 求 出 以下 所 有 人 的 出圈顺 序 . 把 出 圈人 的 编 号按 要 求输 出 出 并
来 。设 有 n个人 坐 一 圈 并 按顺 时 针方 向 从 1到 n编 号 . 第 s 人 开 从 个
嚣 ,
序 12 … , 报 数 , 报 到 N 的 猴 子 退 出 到 圈 外 , 从 下 一 个 猴 子 开 ,, N 凡 再
始 继 续 1到 N 继 续 报 数 , 此 循 环 , 到 圈 内 只 剩 下 一 只猴 子 时 , 如 直 这 只猴 子 就 是 大 王 。 这个 问题 也 是 有 约 瑟 夫 环 延 伸 出 来 的 , 称 为 约 瑟 也 夫环 问题
) vi ie a() odWf D t t fn ;/ 义 整 型变 量 t / i i 定 FL IE / 义 指 向 文件 型 指 针 变 量 / 定
f=oe (O TD ” w )车以写方式 打开 O TD T文件, p fpn ” U .AT , ”; ” , U .A 以便
21 00年
第 2 期 l
SIN E&T C N L G F R A IN CE C E H O O Y N O M TO I
OI 论坛。 T
科技信息
约瑟夫环的 C语言数组的实现
刘文锋 ( 菏泽 学院计 算机 与信 息工程 系 山东 菏泽 24 1 7 0 5)
【 摘 要】 本文给 出了使 用 C语言数组 解决约 瑟夫环的一种方法, 并得到 了预期的结果。 【 关键词 】 瑟夫环 ; 组; 约 数 c语言 O 引言
约瑟夫问题(算法与数据结构课设报告)
线性表的操作及其应用一、问题描述线性表、队列是一种常用的数据结构,有顺序和链式两种存储结构,在实际中应用十分广泛,而链表又分为单链表和循环链表,队列又分为链式队列和循环队列。
这些数据结构都可用来解决约瑟夫环问题。
约瑟夫环问题是算法设计中的一个经典问题,是顺序编号的一组n个人围坐一圈,从第1个人按一定方向顺序报数,在报到m时该人出列,然后按相同方法继续报数,直到所有人出列。
设计算法求约瑟夫环中人员的出列顺序。
二、基本要求1、选择合适的存储结构,建立线性表;2、利用顺序存储结构求解约瑟夫环问题;3、利用单链表和循环链表分别求解约瑟夫环问题;4、利用队列求解约瑟夫环问题。
三、测试数据约瑟夫环的测试数据为7,报数为1至3。
四、算法思想由于用到四种不同的存储结构,它们的算法思想依次是:1、首先建立一个顺序表模拟整个约瑟夫环,手动输入顺序表长(即参加约瑟夫循环的人数)和循环的次数和表元素。
用已经输出总人数和顺序表长作比较,作为外层循环条件。
并对每一个输出后的元素重新赋值以为标记。
对于每次循环,首先检查顺序表此次是不是我们设立的标记,如果不是则循环次数加1,当达到要求的循环次数时就将循环次数设置为0,输出该元素到屏幕并将总输出元素加1。
每次外循环我们都会移到表的下一个位置,作为新的判断条件,每次报到表尾的时候,我们都将重新设置到表尾,作为下次循环的表元素。
2、首先采用链式循环链表建立整个约瑟夫环,手动输入第一次的循环次数和每个人所持下一个循环次数。
设立判断指针指向表头,并将该指针是否为空作为外层循环条件。
做一个内层循环,将判断指针移动到循环要输出的数,并设立一个前指针指向该指针的前一个位置,输出该元素后,将循环次数重新赋值成该元素。
接着判断前指针和判断指针比较,如果相等说明整个表已经输出完毕,否则将删除该位置的元素。
3、用链式队列建立循环约瑟夫环,手动输入人数,第一次的循环次数和每个人所持下一个循环次数。
并将每一个元素依次入队列,根据第一次循环次数,建立一个for循环,每一次循环都出队列,如果达到要求的循环次数就输出,否则进队列,这样这个数字就出现在队尾。
数据结构课程设计环拓扑排序和纸牌游戏 (1)
目录课题一 joseph环 41.1 问题的提出1.1.问题的提出41.2 概要设计2.1算法思想51.3流程图根据算法思想,画程序流程图如下:661.4 源代码1.3.详细设计 7 输入m 、nm>0且n>0的整数建立含n 个结点的链表且用head 指向第一个元素,结点数据域包含password 、No 、以及指向下一结点的指head=>pn ≥2(m%n)==0?n:m%n=>1=>i i<mp →next=>pi++输出p →Nop →password=>m删除p 所指向结点n--输出p →No结束开始1.5 结果与分析.4 测试及性能分析10课题二拓扑排序 112.1 问题的提出2.1 问题的提出112. 2 概要设计112.3 流程图2.根据算法思想,画流程图如下:1212 开始设辅助数组indegree 记录图的各顶点的入度值,并将indegree 数组各变量赋初值。
输入图的顶点数、边数建立一个栈,存储图的顶点的序号用邻接表法建图,并计算出indegree 数组中各变量值根据indegree 数组将入度为0的顶点入栈count 对输出顶点计数0=>count栈不空删除栈顶元素,赋给i count++将与第i 个顶点链接的各顶点入度减1输出第i 个顶点值 顶点入度为0 顶点序号入栈count<G.vexnum输出“拓扑排序成功” 输出“拓扑排序不成功” 结束2.4 源代码132.5 结果与分析2.4 测试及性能分析17课题三纸牌游戏 193.1 问题的提出.1 问题的提出193. 2 概要设计191.当每个号码每次遇到是某个数的倍数时,都会相应的翻一次,这样,每张牌会翻的次数就各不一样,可能很多次,也可能只有一两次,结果就只是要输出在经过各个不同次数的翻牌后,正面向上的牌都有哪几个。
举例说明一下,比如24,第一次它是2的倍数时要从正面翻到背面,当进行到3时,就又要从背面翻回来,而到4时还要在翻,同理呢,到6.8.12…它都要来回的翻。
用顺序表解决约瑟夫环问题
⽤顺序表解决约瑟夫环问题⼀、实验题⽬:约瑟夫环问题:设编号为1,2,3,……,n的n(n>0)个⼈按顺时针⽅向围坐⼀圈,m为任意⼀个正整数。
从第⼀个⼈开始顺时针⽅向⾃1起顺序报数,报到m时停⽌并且报m的⼈出列,再从他的下⼀个⼈开始重新从1报数,报到m时停⽌并且报m的⼈出列。
如此下去,直到所有⼈全部出列为⽌。
要求设计⼀个程序模拟此过程,对任意给定的m和n,求出出列编号序列。
实验要求:⽤顺序表实现。
⼆、设计分析:⾸先创建了⼀个顺序表,并且⽤数组存每个⼈的编号,出列的时候将此编号置为0,代表此位置的⼈已经出列,循环查询编号不为0的元素,并⽤变量j记下当前是第⼏个⼈,当j==m的时候,代表此位置是第m个⼈,输出并将编号置为0,⽤k记录出列⼈的下⼀位的索引,并将数组长度-1,再进⾏新⼀轮的循环,直到所有⼈都出列。
三、程序代码:#include<iostream>#include<cstdlib>using namespace std;const int MaxSize=100;typedef struct Node{int data[MaxSize];int length;}List;void CreateList(List *&L,int n){L=(List *)malloc(sizeof(List*));for(int i=1;i<=n;i++){L->data[i]=i;}L->length=n;}void DispList(List *&L,int m){int len=L->length;int j=0,k=1;while(L->length){for(int i=1;i<=len;i++){if(L->data[k]){j++;}if(j==m){cout<<L->data[k]<<" ";L->data[k]=0;L->length--;j=0;k=(k+1)%(len+1)?(k+1)%(len+1):1;break;}k=(k+1)%(len+1)?(k+1)%(len+1):1;}}}int main(){int m,n;cin>>m>>n;List *L;CreateList(L,n);DispList(L,m);return 0;}。
约瑟夫环问题的两种解法(循环链表和公式法)
约瑟夫环问题的两种解法(循环链表和公式法)问题描述这⾥是数据结构课堂上的描述:N people form a circle, eliminate a person every k people, who is the final survior?Label each person with 0, 1, 2, ..., n - 1, denote(表⽰,指代) J(n, k) the labels of surviors when there are n people.(J(n, k)表⽰了当有 n 个⼈时幸存者的标号)First eliminate the person labeled k - 1, relabel the rest, starting with 0 for the one originally labeled k.0 1 2 3 ... k-2 k-1 k k+1 ... n-1... k-2 0 1 ...Dynamic programmingJ(n, k) = J(J(n - 1, k) + k) % n, if n > 1,J(1, k) = 0⽤中⽂的⽅式简单翻译⼀下就是 (吐槽:为啥课上不直接⽤中⽂呢?淦!) 有 n 个⼈围成⼀圈,从第⼀个⼈开始,从 1 开始报数,报 k 的⼈就将被杀死,然后从下⼀个⼈开始重新从 1 开始报数,往后还是报 k 的⼈被杀掉,杀到最后只剩⼀个⼈时,其⼈就为幸存者。
(上⾯的英⽂是从 0 开始的,是因为我们写程序时使⽤了数组,所以下标从 0 开始)解决⽅案循环链表⽅法算法思路很简单,我们这⾥使⽤了循环链表模拟了这个过程:节点 1 指向节点 2,节点 2 指向节点 3,...,然后节点 N 再指向节点 1,这样就形成了⼀个圆环。
如图所⽰,n 取 12,k 取 3,从 1 开始报数,然后依次删除 3, 6, 9, 12:#include<stdio.h>#include<stdlib.h>typedef struct Node // 节点存放⼀个数据和指向下⼀个节点的指针{int data;struct Node *next;} *NList; // NList为指向 Node 节点的指针// 创建⼀个节点数为 n 的循环链表NList createList(int n){// 先创建⼀个节点NList p, tmp, head;p = (NList)malloc(sizeof(struct Node));head = p; // 保存头节点p->data = 1; // 第⼀个节点for (int i = 2; i <=n ; i++){tmp = (NList)malloc(sizeof(struct Node));tmp->data = i;p->next = tmp;p = tmp;}p->next = head; // 最后⼀个节点指回开头return head;}// 从编号为 1 的⼈开始报数,报到 k 的⼈出列,被杀掉void processList(NList head, int k){if (!head) return;NList p = head;NList tmp;while (p->next != p){for (int i = 0; i < k - 1; i++){tmp = p;p = p->next;}printf("%d 号被杀死\n", p->data);tmp->next = p->next;free(p);p = NULL; // 防⽌产⽣野指针,下同p = tmp->next;}printf("幸存者为 %d 号", p->data);free(p);p = NULL;}int main(){NList head = createList(11);processList(head, 3);return 0;}测试结果:易知,这个算法的时间复杂度为O(nk),显然,这不是⼀个好的算法。
约瑟夫环问题(Josephus)
第一行为一个整数T(<2^15)表示测 试次数,接着第二到T+1行分别为n,m和k 的值。 例:2
10 2 3
输出格式:
T行最后min(n,3)个出列的编号。 结果:6 1 5
问题背景
• 这个问题是以弗拉维奥•约瑟夫斯命名的, 它是1世纪的一名犹太历史学家。他在自己 的日记中写道,他和他的40个战友被罗马 军队包围在洞中。他们讨论是自杀还是被 俘,最终决定自杀,并以抽签的方式决定 谁杀掉谁。约瑟夫斯和另外一个人是最后 两个留下的人。约瑟夫斯说服了那个人, 他们将向罗马军队投降,不再自杀。
(3)us jp=new Josephus(); int a[]=new int[n]; for(int i=0;i<n;i++){ a[i]=i+1; } jp.SortArray(a,n,m,k,g); }
public void show(int[]b,int g){ for(int i=b.length-g;i<b.length;i++){ System.out.print(b[i]+" ");
68 34 25 38 54 4 120 16 23 32 53 97
500 12 30 166 358 266
实验总结:
(1) 经过这次的实践,让我们明白了合作 的重要性。
(2)在程序设计初期,总会或多或少的出现 问题,经过我们的耐心调试,不断地修改, 慢慢地将程序设计较好的符合了要求。
(3)当然其中还是会存在一些漏洞,需要进 一步的改进。在计算机中是容不得丝毫的 错误的,这也让我们学到了面对科学要持 有严谨的态度,否则必定得不到应该有的 结果。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
约瑟夫环
题目:
1、编号为1、
2、3…n的n个人按顺时针方向围成一个圈,每人持有一个密码(正整
数)。
一开始任选一个正整数作为报数的上限值m,从第一个人开始按顺时针方向自1开始报数,报到m时停止报数。
报m的人出列,将他的密码作为新的m值,从他在顺时针方向上的下一个人开始重新从1报数,如此下去,直至所有人全部出列为止。
设计个出列顺序。
2、利用单向循环链表存储结构模拟约瑟夫过程。
按照出列的顺序印出各人的编号
一、需求分析
1、本演示程序过程中,需要手动输入三个变量,总人数n,初值
m(第一个人出列时需要的数),每个人手中拥有的密码。
2、需要用到单向循环链表存储结构模拟此过程,按照出列的顺序
印出各人的编号。
二、概要设计
为实现上述题目要求及需求,应该用单向循环链表存储结构模拟此过程。
抽象数据类型线性表的定义如下:
ADT List {
数据对象:D={ ai | ai ∈ElemSet, i=1,2,...,n, n≥0 }
{称 n 为线性表的表长; 称 n=0 时的线性表为
空表。
}
数据关系:R1={ <ai-1 ,ai >|ai-1 ,ai∈D, i=2,...,n }
{设线性表为 (a1,a2, . . . ,ai,. . ,an),
称 i 为 ai 在线性表中的位序。
} 三、详细设计
#include<stdio.h> //头文件
#include<malloc.h> //动态分配内存文件
typedef struct data //data结构体
{
int num;
int val;
}typdata;
typedef struct node //node 链表结构体
{
typdata data;
struct node*next;
}listnode;
typedef listnode*linklist;
linklist head;
void main()
{
int n,i,b,m,j;
linklist head=(listnode*)malloc(sizeof(listnode));
//动态分配内存
listnode *p,*q;
printf("请输入总人数:");
scanf("%d",&n);
q=head;
for(j=1;j<=n;j++)
{
printf("请输入第 %d 学生的密码: ",j);
scanf("%d",&b);
printf("\n");
q->next=(listnode*)malloc(sizeof(listnode)); //指针操作 q=q->next;
q->data.val=b;
q->data.num=j;
q->next=head->next;
}
printf("请输入初值: ");
scanf("%d",&m);
if(m<=0)
printf("错误!\n");
else
{
printf("结果是:\n");
printf("出列顺序是: ");
do
{
i=1;
while(i!=m)
{
q=q->next;
i++;
}
p=q->next;
q->next=p->next;
printf(" %d",p->data.num);
free(p);
q=q->next;
}
while(q->next!=q);
printf(" %d\n",q->data.num); free(q);
free(head);
}
}
四、调试分析
1、在设计程序初期,由于对结构体把握不好,造成程序中断,无
法继续,但是查阅多方资料,终于弄懂。
2、在结构体运用过程中,指针指向多次犯错,但经过改正,指针
没有问题了。
3、printf(“\n”);写成printf(“%n”);造成程序无法输入,
粗心造成,下次避免。
4、在m的值需要-1的时候不理解程序运行过程,跟踪调试解决。
五、用户手册
本程序简洁明了,在界面就可以看出如何操作,步步均有提示,见下图
六、测试数据
m的初值为20,n=7,7个人的密码以此是:3,1,7,2,4,8,4,首先m的值为6(正确的出列顺序是:6,1,4,7,2,3,5).
测试结果见下图
七、附录
Stdio.h c语言头文件
Malloc.h 动态分配内存函数头文件。