静态数组处理约瑟夫环——算法分析与设计算法实例C语言

合集下载

C实验报告约瑟夫斯环问题

C实验报告约瑟夫斯环问题

约瑟夫斯(Josephus)问题的一种描述是:编号为1,2,…,n的n个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。

一开始任选一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1开始报数,报到m时停止报数。

报m的人出列,将他的密码作为新的m值,从他在顺时针方向下一个人开始重新从1报数,如此下去,直至所有的人全部出列为止。

试设计一个程序,按出列顺序印出各人编号。

2.基本要求:利用单向循环链表存储结构模拟此过程,按照出列的顺序印出各人的编号。

3.测试数据:m的初值为20;n=7,7个人的密码依次为:3,1,7,2,4,8,4。

m初值为6(正确的出列顺序应为6,1,4,7,2,3,5)。

4.简述每一部分的对象、目的和要求:(1)主函数部分:对象:链表;目的:创建新链表;要求:将该链表初始化。

(2)被调函数部分:对象:结构体;目的:创建循环链表并且模拟约瑟夫斯问题;要求:让链表首尾相接,并且释放原来单链表的头结点空间。

通过该函数的调用,依次输出各结点的编号,并且符合规则。

二.需求分析1.程序所能达到的基本可能:该程序用循环链表来模拟n个人顺时针围坐一圈,用链表中的每一个结点代表一个人,结点结构体中设置两个变量,分别存放其编号以及密码。

在输入初始密码后,对该链表进行遍历,直到遍历到第m个结点,释放其空间,使其出列。

然后用被释放空间结点的密码值作为新的密码值,重复上述过程,直至所有结点被释放空间出列,链表成为空链表。

2.输入输出形式及输入值范围:程序运行后显示提示信息:"Please input a data:",提示用户输入密码信息,在输入达预定次数后自动跳出该循环,同时循环链表创建成功,在主函数中有相应的输出给予检验。

然后程序显示提示信息:"Please input the number m:",提示用户输入初始密码,程序执行结束后会输出相应的出列结点的顺序,亦即其编号。

c课程设计约瑟夫环

c课程设计约瑟夫环

c 课程设计约瑟夫环一、教学目标本课程的目标是让学生理解和掌握约瑟夫环的原理及其在计算机科学中的应用。

知识目标包括:了解约瑟夫环的概念、算法实现和数学原理;技能目标涵盖:能够使用至少一种编程语言实现约瑟夫环算法,并进行简单的性能分析;情感态度价值观目标强调:培养学生的逻辑思维能力,激发他们对计算机科学和算法研究的兴趣。

二、教学内容教学内容围绕约瑟夫环的理论基础和实际应用展开。

首先介绍约瑟夫环的基本概念,然后通过编程实践让学生深入理解算法的工作原理。

具体包括:1.约瑟夫环的定义及其在计算机科学中的应用。

2.约瑟夫环算法的不同变体及其实现方法。

3.循环队列的概念及其在约瑟夫环算法中的作用。

4.通过编程练习,掌握至少两种不同的编程语言实现约瑟夫环算法。

三、教学方法为了提高学生的理解能力和实践技能,将采用多种教学方法相结合的方式:1.讲授法:用于解释约瑟夫环的基本概念和数学原理。

2.案例分析法:通过分析具体的约瑟夫环应用实例,加深学生对知识点的理解。

3.实验法:安排实验室实践环节,让学生亲自编写代码实现算法。

4.分组讨论法:鼓励学生在小组内交流想法,共同解决问题,培养团队协作能力。

四、教学资源为了支持课程的顺利进行,将准备以下教学资源:1.教材:《计算机科学基础》相关章节。

2.参考书籍:提供关于算法和数据结构的进阶阅读材料。

3.多媒体资料:制作PPT和视频教程,辅助学生理解复杂概念。

4.编程环境:为学生提供合适的编程环境和在线编程平台。

5.实验设备:确保实验室中每名学生都有足够的机器进行编程实践。

五、教学评估教学评估是衡量学生学习成果的重要手段。

本课程的评估方式包括:平时表现(30%)、作业(20%)、小测验(20%)、实验报告(20%)和期末考试(10%)。

平时表现评估将基于学生的课堂参与、提问和小组讨论;作业将主要是编程练习,旨在巩固课堂所学;小测验将定期进行,以检查学生的理解程度;实验报告将评价学生对实验操作的理解和分析能力;期末考试将涵盖所有课程内容,测试学生的综合理解能力。

约瑟夫环-joseph环-数据结构与算法课程设计报告

约瑟夫环-joseph环-数据结构与算法课程设计报告

合肥学院计算机科学与技术系课程设计报告2009~2010学年第二学期课程数据结构与算法课程设计名称joseph环学生姓名朱玉庭学号0804012029专业班级08计本(2)指导教师王昆仑、张贯虹2010 年06月08号一、问题分析和任务定义:约瑟夫环是一个数学游戏,根据游戏内容的描述,能够很容易的看出,游戏中的玩家顺时针围坐一圈,能够很容易的发现,这跟本课上的单循环链表非常相似,所以可以通过单循环链表存储结构模拟此过程,当游戏中的玩家出列时,可以通过删除单循环链表中的结点来实现。

二、数据结构的选择和概要设计:选择带为指针的单循环链表来解决这个问题,先建立一个空链表,然后根据人数生成具有相应结点的单循环链表,知道密码后,通过循环来找到对应的结点,然后将该结点的编号输出,改变密码,最后删除结点,以此类推,知道编码全部输完,即可得到结果序列。

三、详细设计和编码:本题目是通过单循环链表存储结构来模拟此过程的,首先要先明确该单循环链表中结点的结构类型,定义如下:typedef struct Node{int key; //每个人持有的密码int num; //这个人的编号struct Node *next; //指向下一个结点}Link;当生成单循环链表时,就需要用到课本上创建单循环链表的有关内容了,可以先通过子函数Link *InitList()建立一个空链表,返回指针L,然后将返回的指针代入子函数Link *Creater(Link *L,int n)的形参中,对循环链表进行初始化,并且也返回一个指针,然后再将这个返回的指针代入到输出函数void Output(Link *L,int n,int m)的形参中,要想根据题目要求完成序列的输出,需要通过两个for循环来实现,第一个循环for(i=1;i<=n;i++) ,因为一个用n个人,所以结果要输出n个编号,这个循环每循环一次输出一个编号即printf("%d ",q->num),并将该编号下的密码赋值给m 即m=q->key,当循环完毕时正好将编号全部输出,第二个循环for(j=1;j<m;j++) p=p->next; q=p->next; 用以找到相应的结点,并用指针q指向它,当完成了编号的输出和密码的赋值后,删除q指向的结点,将两个循环适当结合,即可输出正确的结果序列,其中的人数n和初始密码在主函数中确定。

约瑟夫环问题源代码(C语言)

约瑟夫环问题源代码(C语言)

约瑟夫环问题如下:已知n个人(n>=1)围桌一园桌周围,从1开始顺序编号。

从序号为1的人开始报数,顺时针数到m的那个人出列。

他的下一个人又从1开始报数,数到m的那个人又出列。

依此规则重复下去,直到所有人全部出列。

求解最后一个出列的人的编号。

本次实验是以顺序表求解约瑟夫环问题,程序流程图及程序运行结果如下:输入人数、所报数、第一个报数人编号存储并建立一个约瑟夫环通过循环结构依次查找每次出列的人的编号并输出输出最后一个出列的人的编号程序代码如下:#include<iostream>#include<process.h>#include<stdlib.h>using namespace std;struct Node //循环节点的定义{int number; //编号Node *next;};Node *CreateList(Node *L,int &n,int &m); //建立约瑟夫环函数void Joseph(Node *L,int n,int m); //输出每次出列号数函数Node *DeleteList(Node **L,int i,Node *q); //寻找每次出列人的号数int LengthList(Node *L); //计算环上所有人数函数void main() //主函数{system("color 75"); //设置颜色以美观Node *L;L=NULL; //初始化尾指针int n, m;cout<<"请输入人数N:";cin>>n; //环的长度if(n<1){cout<<"请输入正整数!";} //人数异常处理else{cout<<"请输入所报数M:";cin>>m;if(m<1){cout<<"请输入正整数!";} //号数异常处理else{L=CreateList(L,n,m); //重新给尾指针赋值Joseph(L,n,m);}}system("pause");}Node *CreateList(Node *L,int &n,int &m) //建立一个约瑟夫环(尾插法){Node *q;for(int i=1;i<=n;i++){Node *p;p=new Node;p->number=i;p->next=NULL;if(i==1) L=q=p; //工作指针的初始化 else{q->next=p;q=q->next;}}q->next=L;if(L!=NULL){return(L);} //返回尾指针else cout<<"尾指针异常!"<<endl; //尾指针异常处理}void Joseph(Node *L,int n,int m) //输出每次出列的人{int k;cout<<"请输入第一个报数人:";cin>>k;if(k<1||k>n){cout<<"请输入1-"<<n<<"之间的数"<<endl;}else{cout<<"\n出列顺序:\n";for(int i=1;i<n;i++){Node *q = new Node;if(i==1) q=DeleteList(&L,k+m-1,q); //第一个出列人的号数else q=DeleteList(&L,m,q);cout<<"号数:"<<q->number<<endl;delete q; //释放出列人的存储空间}cout<<"最后一个出列号数是:"<<L->number<<endl; //输出最后出列人的号数}}Node *DeleteList(Node **L,int i,Node *q) //寻找每次出列的人{if(i==1) i+=LengthList(*L); //顺序依次出列情况的处理方式Node *p;p=*L;int j=0;while(j<i-2) {p=p->next;j++;}q = p->next;p->next=p->next->next;*L = p->next;return(q);}int LengthList(Node *L) //计算环上的人数{if(L){cout<<"尾指针错误!"<<endl;} //异常处理else{int i=1;Node *p=L->next;while(p!=L){i++;p=p->next;}return(i);}}实验体会:通过对本问题的分析,我进一步熟悉了对各种逻辑表达式的判断和指针的使用。

C语言约瑟夫环问题

C语言约瑟夫环问题

C语言约瑟夫环问题编号为1,2,3,…,n 的n 个人围坐一圈,任选一个正整数m 作为报数上限值,从第一个人开始按顺时针方向报数,报数到m 时停止,报数为m 的人出列。

从出列人的顺时针方向的下一个人开始又从1 重新报数,如此下去,直到所有人都全部出列为止。

算法思想每个人的编号存放在一个数组a 中,主函数中决定人数的个数以及报数的上限值m,设计一个函数实现对应的操作。

函数的形参有整型数组a、整数n 和m,n 用来接收传递的人数,m 用来接收报数上限,函数的返回值为空;函数体中输出出列人的顺序。

函数中利用循环访问数组中n 个元素,每次访问元素,设定内循环连续访问m 个元素,元素访问的下标为k,访问到第m 个元素时,如果元素不是0,此时输出元素a[k],再设定a[k] 为0,继续访问后面的元素。

主函数中设定数组a,从键盘输入n 和m,利用循环产生n 的位置序号存放到数组a 中,调用函数实现相应的操作。

程序代码1.#include<stdio.h>2.#define N 1003.int josef(int a[],int n,int m)4.{5.int i,j,k=0;6.for(i=0;i<n;i++)7.{8. j=1;9.while(j<m)10.{11.while(a[k]==0)12. k=(k+1)%n;13. j++;14. k=(k+1)%n;15.}16.while(a[k]==0)17. k=(k+1)%n;18.printf("%d ",a[k]);19. a[k]=0;20.}21.return0;22.}23.24.int main()25.{26.int a[100];27.int i,j,m,n;28.printf("input n and m:");29.scanf("%d%d",&n,&m);30.for(i=0;i<n;i++)31. a[i]=i+1;32.printf("\n output:\n");33.josef(a,n,m);34.printf("\n");35.return0;36.}调试运行结果15 个人围坐在一起,报数上限为4 时的出列顺序如下所示:100 个人围坐在一起,报数上限为9 时的出列顺序如下所示:。

约瑟夫环C 代码及实验报告

约瑟夫环C  代码及实验报告

{
outArray[k]=listArray[j];// 将 该 元 素 放 置 到 出 列 数 组
里,并输出
cout<<outArray[k]<<" ";
k++;
listArray[j]=0; //将出列元素置 0
i=1; //下一个元素从 1 开始重新报数
}
else
i++; //报数编号与出列编号不同时,继续报数
if(a[i]==1) {
j=j+a[i]; if(j==m) {
j=0; a[i]=0; k++; cout<<i<<" "; }
} if(i==n)
i=0; }
}
七、实验心得 李孟琪:该实验利用数组实现线性表,算法简便,但产生很多不必要的消耗,下 一步可以尝试采用单链表,双链表实现该问题。 李春阳:通过利用链表编写约瑟夫环,进一步掌握了约瑟夫环的原理,加深了对 链表使用的理解 雷鹤:这次实验遇到的最大问题是拘泥于基本要求中的利用数组来实现线性表, 并用线性表来实现约瑟夫环问题,在尝试用链表实现后问题变得简单了些;在插 入元素这一步费不少时间,头尾节点的移动关系也需要理解
四、详细设计
程序代码:
#include <iostream>
using namespace std;
main()
{
int n,m,k,j;
//n 为总人数,m 为出列编号
cin>>n>>m;
int *listArray=new int[n]; //将 n 个人放在大小为 n 的数组中

约瑟夫环C语言

约瑟夫环C语言

约瑟夫环问题:算法思想:1.对报值m进行求模运算,模就是要取的那个人得编号;当模为0时取最后一个人的编号。

2.当模不为0时,每次取出一个人后对人重新排序。

令抽出的者的后一位排到第一个。

3.重复第1.2两部。

直到所有人全部出列。

缺点:算法的时间复杂度太高,每次抽出一个人后都要重新排序。

#include<stdio.h>struct list{int code;int num;}s[100],d[100],e[100];int fuc(struct list n[],int a,int b){int i,j=0,t=0;while(a){ /*a为队列中剩余人的个数*/if(b%a){ /*对输入上限值进行求模运算*/t=b%a-1; /*t为编号为b%a的人实际在数据中的位置*/d[j]=n[t]; /*将其存放入一个新的结构数组中*/for(i=t;i<a-1;i++){ /*将t之后的元素全部往前挪一位*/n[i]=n[i+1];}a--; /*队列中人数少一个*/paixu(n,a,t); /*重新排序*/}else{t=a-1;d[j]=n[t];a--;}b=d[j].code; /*令b为抽出者的密码*/j++; /*新数组+1*/}return(0);}int paixu(struct list n[],int a,int t){int i=0,j=0;for(i=0;i<a;i++){e[i]=n[i];}for(i=t;i<a;i++){n[j]=e[i];j++;}for(i=0;i<t;i++){n[j]=e[i];j++;}return(0);}改进后的功能函数int fuc(struct list n[],int a,int b){int i=0,j=0,t=0;while(t<a){if(n[i].code!=0) j++;if(j==b){printf("%4d",n[i].code);b=n[i].code;n[i].code=0;t++;j=0;}i++;if(i==a) i=0;}printf("\n");}。

C语言用数组解决约瑟夫环问题

C语言用数组解决约瑟夫环问题

C语言用数组解决约瑟夫环问题C语言用数组解决约瑟夫环问题问题说明:在罗马人占领乔塔帕特后,39 个犹太人与约瑟夫及他的朋友躲到一个洞中,大家决定宁愿自杀也不要被敌人抓到,于是确定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。

然而约瑟夫和他的朋友并不想死去,那么他应该怎样安排他和他的朋友的位置,才能逃脱这场死亡游戏呢?有N个编号为1~N的`人围成一圈,现在每隔两个人(比如:1、4 之间隔了2、3)就将一个人淘汰出去,问最后剩下的是编号为几的人?算法代码如下:#include#includeint main(void){int people_count = 0;int *peoples = NULL;printf("please input people number: ");scanf("%d", &people_count);if (people_count < 2){printf("can't do Joseph\n");}peoples = (int *)calloc(people_count, sizeof(int));int i;for(i = 0; i < people_count; i++){peoples[i] = i+1;}i = 0;int j = 0;int rest = people_count;while(rest){if (i >= people_count){i %= people_count;}if (peoples[i] == 0){i++;continue;}if (j++ % 3 ==0 && rest > 1){printf("kill people NO. %d\n", peoples[i]); peoples[i] = 0;rest--;}else if (rest==1){printf("NO. %d is alive\n", peoples[i]); rest--;}i++;}system("pause");return 0;}。

C语言基于循环链表解决约瑟夫环问题的方法示例

C语言基于循环链表解决约瑟夫环问题的方法示例

C语⾔基于循环链表解决约瑟夫环问题的⽅法⽰例本⽂实例讲述了C语⾔基于循环链表解决约瑟夫环问题的⽅法。

分享给⼤家供⼤家参考,具体如下:概述:约瑟夫环问题,是⼀个经典的循环链表问题,题意是:已知 n 个⼈(以编号1,2,3,…,n分别表⽰)围坐在⼀张圆桌周围,从编号为 k 的⼈开始顺时针报数,数到 m 的那个⼈出列;他的下⼀个⼈⼜从 1 还是顺时针开始报数,数到 m 的那个⼈⼜出列;依次重复下去,要求找到最后出列的那个⼈。

例如有 5 个⼈,要求从编号为 3 的⼈开始,数到 2 的那个⼈出列:出列顺序依次为:编号为 3 的⼈开始数 1,然后 4 数 2,所以 4 先出列;4 出列后,从5 开始数 1,1 数 2,所以 1 出列;1 出列后,从2 开始数 1,3 数 2,所以 3 出列;3 出列后,从 5 开始数 1,2 数 2,所以 2 出列;最后只剩下 5 ⾃⼰,所以 5 出列。

代码实现:#include <stdio.h>#include <stdlib.h>typedef struct node{int number;struct node * next;}person;person * initLink(int n){person * head=(person*)malloc(sizeof(person));head->number=1;head->next=NULL;person * cyclic=head;for (int i=2; i<=n; i++) {person * body=(person*)malloc(sizeof(person));body->number=i;body->next=NULL;cyclic->next=body;cyclic=cyclic->next;}cyclic->next=head;//⾸尾相连return head;}void findAndKillK(person * head,int k,int m){person * tail=head;//找到链表第⼀个结点的上⼀个结点,为删除操作做准备while (tail->next!=head) {tail=tail->next;}person * p=head;//找到编号为k的⼈while (p->number!=k) {tail=p;p=p->next;}//从编号为k的⼈开始,只有符合p->next==p时,说明链表中除了p结点,所有编号都出列了,while (p->next!=p) {//找到从p报数1开始,报m的⼈,并且还要知道数m-1de⼈的位置tail,⽅便做删除操作。

C语言程序设计漫谈之从“约瑟夫问题”谈起

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语言数组实现约瑟夫环问题,以及对其进行时间复杂度分析

C语言数组实现约瑟夫环问题,以及对其进行时间复杂度分析

C 语⾔数组实现约瑟夫环问题,以及对其进⾏时间复杂度分析尝试表达本⼈试着去表达约瑟夫环问题:⼀群⼈围成⼀个圈,作这样的⼀个游戏,选定⼀个⼈作起点以及数数的⽅向,这个⼈先数1,到下⼀个⼈数2,直到数到游戏规则约定那个数的⼈,⽐如是3,数到3的那个⼈就离开这个游戏;按这样的规则,剩下⼀个⼈,游戏就结束,这个⼈就为赢家。

(读者可以试着表达,不认同,直接忽略)抽象分析这个⼈就是⼀个数据个体,数据结点,数据元素。

上⾯产⽣的数据结构为:单⽅向循环的链。

可以⽤链表实现,也可以⽤数组来实现。

链表到数组的迁移⼈(数据元素、数据结点、数据个体)结点关系(结构关系结点移动)范型“指针”定义:能够定位到下⼀个结点(变)“指针“移到下⼀个结点拿到下⼀个结点的”指针“即可,⼀般都有作“移动”变量,移动变量变,就相当于移动。

删除结点数组连续的数组元素(基本数据类型,机构体)数组元素⾥⾯保存有下个结点元素的数组元素下标position 。

arrayname 固定的,只要给出position ,就可以算是定位到数组元素≈poisiton []move =array[move]元素内容 = -1(数组的⼤⼩固定)链表离散的链表结点(结构体)结构体⾥⾯保存有下⼀个结点的指针node* nextpoiter 直接定位到结点,在结合常员变量,就可以拿到数据=poiter ->move = move ->next销毁画图分析:代码实现:#include<stdio.h>#include<stdlib.h>/*Function:遍历数组实现的约瑟夫环。

traverse_joseph_circle_array*param:int[] array,int tail*return: void* 假设是⽤数组实现的约瑟夫环链⼀定存在。

* */void traverse_joseph_circle_array (int array[], int tail ){//数组保存的是下个结点的“指针”,只不过这个指针要通过array 才能够拿到结点的元素,因为array 是固定的,只要变换指针就能够变换结点。

约瑟夫环的C语言数组的实现

约瑟夫环的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 引言

约瑟夫环的C语言数组实现

约瑟夫环的C语言数组实现

约瑟夫环的C语⾔数组实现约瑟夫环问题的具体描述是:设有编号为1,2,……,n的n个(n>0)个⼈围成⼀个圈,从第1个⼈开始报数,报到m时停⽌报数,报m的⼈出圈,才从他的下⼀个⼈起重新报数,报到m时停⽌报数,报m的出圈,……,如此下去,知道剩余1个⼈为⽌。

当任意给定n和m后,设计算法求n个⼈出圈的次序。

⼀开始看到这这个题⽬就是觉得这是⼀个环形的,想到了⽤链表和⽤指针,然后看题⽬的要求是使⽤数组实现。

就先暂时放弃⽤链表的办法,⽤数组实现之后再⽤链表来实现。

⼀开始的思路是:1、建⽴⼀个长度为n的数组。

2、取出位置编号为(i+1)*m的数显⽰,将位置编号为(i+1)*m的数置0;3、第⼀轮取完之后的数再组成⼀个新的数组,⽤2的办法再取;4、重复3的操作,最后剩下m-1个数字。

经过实际编程调试发现这个办法很难实现,效率特别低,容易出错,仅仅是第⼀轮取完数字再组成⼀个新的数组就很费劲了,如果数字⽐较少的话可以直接算出来,如果数据量⼤,就很⿇烦。

后来,就反思⼀开始的思路其实就是模拟了⼀个“环“,通过好多数组来拼接⼀个环。

这样就很⿇烦,逻辑上也很混乱,最后也是看了其他⼈的代码,觉得⽤指针的思想到最后⼀个数的时候跳到第⼀个就可以了。

最早的时候我也有想到过⽤指针的思想去解决,但是不会⽤,主要原因是因为我不知道有这样i = (i + m -1) % n⼀个公式,公式中i就是出圈的那个数字,知道了这个公式之后就是每次需要把出圈的数字删除了就可以,继续⽤这个公式找到下⼀个需要出圈的数字。

最后找到只剩⼀个的时候跳出,中间如果找到某⼀时刻数组的最后⼀个数字的时候跳到第⼀个就可以了,这样就形成了⼀个环。

根据这个思路完成了下边的这个程序,这个程序是7个数,报3出圈。

#include <stdio.h>#include <string.h>int main(){int m = 3;int n = 7;int a[7] = {1,2,3,4,5,6,7};int i;int j;for(i = 0; i < n; i++){a[i] = i+1;}while (n > 1){i = (i + m - 1) % n;printf("第⼀个出圈的是%d\n",a[i]);for(j = i+1; j < n; j++){a[j-1] = a[j];}n--;if(i == n){i = 0;}}printf("最后剩下的是%d\n", a[i]);return0;}上边这段代码在调试的过程中出了⼀个⾮常低级的错误,编译完成后开始运⾏的时候发现,程序确实在运⾏但是什么都不显⽰,就开始⼀点⼀点的调试,发现问题出在了循环部分,发现循环内部是没有问题的,按照逻辑分析是可以跳出循环的,⽽且循环中是有显⽰的,如果不能跳出循环肯定会连续的显⽰,后来就意识到是没有进⼊到循环中,⼜看了很多遍程序才发现是在while(n > 1)这句话后边加了“;”号,这样的低级错误确实不应该,编程太少,所以找到错误花了⽐较长的时间,还是需要多⾃主编程,积累经验。

详解约瑟夫环问题及其相关的C语言算法实现

详解约瑟夫环问题及其相关的C语言算法实现

详解约瑟夫环问题及其相关的C语⾔算法实现约瑟夫环问题N个⼈围成⼀圈顺序编号,从1号开始按1、2、3......顺序报数,报p者退出圈外,其余的⼈再从1、2、3开始报数,报p的⼈再退出圈外,以此类推。

请按退出顺序输出每个退出⼈的原序号算法思想⽤数学归纳法递推。

⽆论是⽤链表实现还是⽤数组实现都有⼀个共同点:要模拟整个游戏过程,不仅程序写起来⽐较烦,⽽且时间复杂度⾼达O(nm),若nm⾮常⼤,⽆法在短时间内计算出结果。

我们注意到原问题仅仅是要求出最后的胜利者的序号,⽽不是要读者模拟整个过程。

因此如果要追求效率,就要打破常规,实施⼀点数学策略。

为了讨论⽅便,先把问题稍微改变⼀下,并不影响原意:问题描述: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-2k-1 --> n-1变换后就完完全全成为了(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)实现⽅法⼀、循环链表建⽴⼀个有N个元素的循环链表,然后从链表头开始遍历并计数,如果基数i == m,则踢出该元素,继续循环,直到当前元素与下⼀个元素相同时退出循环#include <stdio.h>#include <stdlib.h>#include <string.h>typedef struct lnode{int pos;struct lnode *next;} lnode;/*** 构建循环链表&&循环遍历*/void create_ring(lnode **root, int loc, int n){lnode *pre, *current, *new;current = *root;pre = NULL;while (current != NULL) {pre = current;current = current->next;}new = (lnode *)malloc(sizeof(lnode));new->pos = loc;new->next = current;if (pre == NULL) {*root = new;} else {pre->next = new;}// 循环链表if (loc == n) {new->next = *root;}}/*** 约瑟夫环*/void kickoff_ring(lnode *head, int p){int i;lnode *pre, *pcur;pre = pcur = head;while (pcur->next != pcur) {for (i = 1; i < p; i ++) {pre = pcur;pcur = pcur->next;}printf("%d ", pcur->pos);pre->next = pcur->next;free(pcur);pcur = pre->next;}printf("%d\n", pcur->pos);free(pcur);}void print_ring(lnode *head){lnode *cur;cur = head;while (cur->next != head) {printf("%d ", cur->pos);cur = cur->next;}printf("%d\n", cur->pos);}int main(){int i, p, n;lnode *head;while (scanf("%d %d", &n, &p) != EOF) { // 构建循环链表for (i = 1, head = NULL; i <= n; i ++) create_ring(&head, i, n);// 约瑟夫环if (p != 1)kickoff_ring(head, p);elseprint_ring(head);}return 0;}/************************************************************** Problem: 1188User: wangzhengyiLanguage: CResult: AcceptedTime:110 msMemory:912 kb****************************************************************/⼆、数组模拟思想跟循环链表类似,少了构建循环链表的过程#include <stdio.h>#include <stdlib.h>int main(){int i, index, p, n, remain, delete[3001], flag[3001] = {0};while (scanf("%d %d", &n, &p) != EOF) {remain = n;index = 0;while (remain >= 1) {for (i = 0; i < n; i ++) {if (flag[i] == 0) {// 报数index ++;// 报p者退出圈外if (index == p) {// 退出圈外flag[i] = 1;// 重新报数index = 0;delete[remain - 1] = i + 1;remain --;}}}}// 输出每个退出⼈的序号for (i = n - 1; i >= 0; i --) {if (i == 0) {printf("%d\n", delete[i]);} else {printf("%d ", delete[i]);}}}return 0;}三、数学推导#include <stdio.h>int main(void){int i, n, m, last;while (scanf("%d", &n) != EOF && n != 0) {// 接收报数scanf("%d", &m);// 约瑟夫环问题for (i = 2, last = 0; i <= n; i ++) { last = (last + m) % i;}printf("%d\n", last + 1);}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),显然,这不是⼀个好的算法。

C语言约瑟夫环课程设计

C语言约瑟夫环课程设计

C语言约瑟夫环课程设计一、教学目标本节课的教学目标是使学生掌握约瑟夫环的原理及其在C语言中的实现。

知识目标包括:理解约瑟夫环的概念、熟悉C语言的基本数据结构和算法。

技能目标则要求学生能够运用C语言实现约瑟夫环问题,并具备一定的调试能力。

情感态度价值观目标则是培养学生的逻辑思维能力,提高他们解决实际问题的兴趣和信心。

二、教学内容本节课的教学内容主要包括两个部分:首先是约瑟夫环的理论基础,包括其概念、原理和应用;其次是C语言的编程实践,包括算法设计、代码编写和调试。

教材选用《C程序设计》一书,具体涉及第7章“循环结构”的内容。

三、教学方法为了达到本节课的教学目标,将采用多种教学方法相结合的方式。

首先是讲授法,用于讲解约瑟夫环的理论基础;其次是讨论法,鼓励学生针对实际问题进行思考和交流;再次是案例分析法,通过分析具体案例,使学生掌握算法设计和代码编写技巧;最后是实验法,让学生在实际操作中提高编程能力。

四、教学资源为了支持教学内容和教学方法的实施,将准备以下教学资源:教材《C程序设计》、参考书《C语言程序设计教程》、多媒体教学课件、在线编程平台和调试工具。

此外,还将利用网络资源,如教学视频、博客和论坛,为学生提供更多的学习资料和实践机会。

五、教学评估本节课的评估方式将采用多元化评价体系,全面反映学生的学习成果。

评估方式包括:平时表现、作业、考试和课堂讨论。

平时表现主要考察学生的出勤、纪律和参与度;作业则主要考察学生的编程能力和理解程度;考试则是对学生整体掌握情况的考察;课堂讨论则主要评估学生的思考能力和团队合作精神。

评估方式将尽量客观、公正,确保全面反映学生的学习成果。

六、教学安排本节课的教学安排将紧凑、合理,确保在有限的时间内完成教学任务。

教学进度将按照教材的章节进行,每个章节安排2-3节课的时间。

教学时间将安排在正常上课时间内,地点则选择计算机实验室,以便学生进行实践操作。

同时,教学安排还将考虑学生的实际情况和需要,如学生的作息时间、兴趣爱好等,尽量让学生在舒适的环境中学习。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
#include<string.h>
#include<stdio.h>
#include<windows.h>
#include<malloc.h>
#define Man 3
void josephus(int num,int alive,int kill)
{
int man[100]={0};
system("pause");
return 0;
}
printf("被淘汰的号码数\n");
scanf("%d",&kill);
printf("约瑟夫环中人数:\n");
scanf("%d",&num);
printf("最后环中剩余的人数:\n");
scanf("%d",&alive);
josephus(num,alive,kill);
i++;
if(i==kill) //被淘汰
{
i=0;
break;
}
}while(1);
man[pos]=count; //在约瑟夫环中初始化的编号
printf("第%2d个人自杀!约瑟夫环编号%2d\n",pos+1,man[pos]);
puts("\n");
count++; //记录已经自杀的人数
}
printf("\n");
alive=num-alive;
for(i=0;i<num;i++)
{
if(man[i]>=alive)
printf("初始编号:%d,约瑟夫环编号:%d\n",i+1,man[i]);
}
puts("\n");
}
int main() 来自{ int num;
int alive;
int kill;
int count=1;
int i=0;
int pos=-1;
while(count<num)
{
do
{
pos=(pos+1)%num; //循环多圈的环处理,数组从零开始记录
if(man[pos]==0) //没有被赋值(没有自杀的人)
相关文档
最新文档