数据结构《约瑟夫环》

合集下载

约瑟夫环(内含源代码)

约瑟夫环(内含源代码)

数据结构课程设计实验学校:江西农业大学班级:软件1115班姓名:***学号:********课程:数据结构课程设计指导教师:***实验一:约瑟夫问题问题简述:约瑟夫环是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。

从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。

约瑟夫问题是由古罗马著名的史学家Josephus提出的问题演变而来,所以通常称为Josephus问题。

改进约瑟夫问题的描述是:编号为1,2,…,n的n个人按顺时针方向围坐一圈, 每人有一个密码Ki(整数),留作其出圈后应报到Ki 后出圈。

报数方法采用顺时针报数和逆时针报数交替进行,初始密码可任意确定。

求最后剩下的人的编号。

这个就是约瑟夫环问题的实际场景,后来老师要求我们对要求中的每人所持有的密码以及第一次的报数上限值要用随机数产生。

因此约瑟夫环问题如果采用双向循环链表则能很好的解决。

循环链表的数据结构,就是将一个链表的尾元素指针指向队首元素。

p->link=head解决问题的核心步骤:先建立一个具有n个链结点,无头结点的循环链表,然后确定第一个报数人的位置,并不断地从链表中删除链结点,直到链表为空。

一、题目内容及要求【问题描述】编号是1,2,……,n的n个人按照顺时针方向围坐一圈,每个人只有一个密码(正整数)。

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

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

设计一个程序来求出出列顺序。

【要求】利用单向循环链表存储结构模拟此过程,按照出列的顺序输出各个人的编号。

2)掌握线性表的基本操作,如插入、删除、检索等在链式存储结构上的运算。

二、实验环境(硬/软件要求):Windows XP +三、概要设计利用单向循环链表存储结构模拟此过程,因为循环链表最后一个结点的指针域指向头结点,整个链表形成一人环,刚好和题中的“n个人按照顺时针方向围坐一圈,每个人只有一个密码(正整数)”内容要求一致,而且,循环链表中任一结点出发均可找到表中其他结点,利用这一优点可较容易地找出报数的人及下一个报数的人,最后按照出列的顺序用一个for语句实现。

实验报告——约瑟夫环

实验报告——约瑟夫环

《数据结构》课程设计报告课程名称:《数据结构》课程设计课程设计题目:约瑟夫环姓名:张光栋院系:计算机学院专业:网络工程年级: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.第一次写时,没有区分出只剩下的一个的情况,导致最终输出出现错误。

数据结构实验第二章约瑟夫环

数据结构实验第二章约瑟夫环

实验名称:约瑟夫环一.问题描述:设有编号为1,2,…,n的n(n>0)个人围成一个圈,每个人持有一个密码 m。

从第一个人开始报数,报到 m 时停止报数,报 m 的人出圈,再从他的下一个人起重新报数,报到 m 时停止报数,报 m 的出圈,……,如此下去,直到所有人全部出圈为止。

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

二、数据结构设计由于约瑟夫环问题本身具有循环性质,故考虑采用循环链表的结构来存储信息。

为了统一对表中任意结点的操作,循环链表不带头结点。

其结点类型定义如下:typedef struct Node{int data;struct Node *next;}Node,*LinkList;三、算法设计(1)流程图定义L头指针,创建头结点创建循环链表求具体出圈顺序(2)详细说明:求出圈顺序://首先,定义L头指针,创建头结点LinkList L,p,q;i=1;L=(LinkList)malloc(sizeof(Node));L->data=i;p=L;//然后,创建循环链表for(i=2;i<=n;i++){ //n为总人数q=(LinkList)malloc(sizeof(Node));q->data=i;p->next=q;p=p->next;}p->next=L;p=L;//求具体出圈顺序while(1){i=1;while(i<m-1){ //m为密码p=p->next;i++;}if(p->next==p){ //判断是否到最后一个结点printf("\nthe last one is: %d\n",p->next->data);break;}else{++num;printf("\nthe %dth one is: %d",num,p->next->data);p->next=p->next->next;}p=p->next;}四、界面设计,此程序功能简单,无需复杂操作界面。

数据结构(五)-环形链表及约瑟夫问题

数据结构(五)-环形链表及约瑟夫问题

数据结构(五)-环形链表及约瑟夫问题⼀、单向环形链表的应⽤场景(约瑟夫问题)Josephu 问题为:设编号为1,2, ... n 的 n 个⼈坐成⼀圈,约定从编号为 k(n≥k≥1) 的⼈开始报数,数到 m 的那个⼈出列,她的下⼀位⼜从 1 开始报数,数到 m 的那个⼈⼜出列,以此类推,直到所有⼈出圈为⽌,因此形成⼀个出圈编号的序列⼆、单向链表的⽰意图三、创建环形链表图解创建环形链表代码实现// 创建单向环形链表class SingleCircularLinkedList{// 初始化⼀个头节点Girl first = null;// 添加数据到链表中public void add(int num) {// 校验参数if(num < 1) {System.out.println("您输⼊的⼩孩个数⼩于1,不能创建环形链表");}// 定义临时指针Girl curGirl = first;for(int i = 1; i <= num; i++) {Girl girl = new Girl(i);if(i == 1) { // 说明是第⼀个节点first = girl;first.setNext(first);curGirl = first;}else {curGirl.setNext(girl);curGirl = girl; // curGirl 后移curGirl.setNext(first); // 形成闭环}}}// 遍历链表public void list() {// 判断链表是否为空if(first == null) {System.out.println("当前链表为空");return;}// 定义临时指针Girl curGirl = first;while(true) {System.out.printf("⼩孩编号为 %d \n", curGirl.getNo());if(curGirl.getNext() == first) {break;}curGirl = curGirl.getNext();}}}// 创建节点类class Girl {private int no;private Girl next;public Girl(int no) {super();this.no = no;}public int getNo() {return no;}public void setNo(int no) {this.no = no;}public Girl getNext() {return next;}public void setNext(Girl next) {this.next = next;}}四、约瑟夫问题图解补充,设置 helper 节点的思路来源于单向链表删除节点时,指针始终指在当前节点的前⼀位,cur.next = cur.next.next代码实现// 约瑟夫问题public void joseph(int startNo, int countNum, int nums) {// 参数校验if(startNo < 1 || countNum > nums || nums < 1) {System.out.println("输⼊的参数有误");return;}// 定义临时指针Girl helper = first;// 让helper移动到first的上⼀个节点的位置,让first指针移动到startNo处(移动startNo - 1次) while(true) {if(helper.getNext() == first) {break;}helper = helper.getNext();}for(int i = 0; i < startNo - 1; i++) {first = first.getNext();helper = helper.getNext();}// 让first和helper同时移动countNum - 1次,⼩孩出圈while(true) {if(helper == first) { // 条件成⽴说明圈中只有⼀个⼩孩break;}for(int i = 0; i < countNum - 1; i++) {first = first.getNext();helper = helper.getNext();}// ⼩孩出圈操作System.out.printf("出圈的⼩孩为 %d 号\n", first.getNo());first = first.getNext();helper.setNext(first);}// 输出圈中留下的lucky girlSystem.out.printf("留在圈中的 lucky girl 为 %d 号\n", first.getNo());}。

约瑟夫环数据结构实验

约瑟夫环数据结构实验

实验1约瑟夫环问题背景约瑟夫问题(Josephus Problem)据说著名犹太历史学家Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。

然而Josephus 和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。

原题:用户输入M,N值,N个人围成一个环,从0号人开始数,数到M,那个人就退出游戏,直到最后一个人求最后一个剩下的人是几号?问题描述设编号为1-n的n(n>0)个人按顺时针方向围成一圈.首先第1个人从1开始顺时针报数.报m的人(m 为正整数).令其出列。

然后再从他的下一个人开始,重新从1顺时针报数,报m的人,再令其出列。

如此下去,直到圈中所有人出列为止。

求出列编号序列。

基本要求需要基于线性表的基本操作来实现约瑟夫问题需要利用顺序表来实现线性表输入输出格式输入格式:n,m输出格式1:在字符界面上输出这n个数的输出序列输出格式2:将这n个数的输出序列写入到文件中测试用例(举例)输入:10,3输出:3 6 9 2 7 1 8 5 10 4课后选做内容(1)使用单链表来实现之(2)使用循环链表来实现之课后习题请以O(n)的时间复杂度来实现约瑟夫问题。

HUNAN UNIVERSITY实验报告题目:约瑟夫环问题学生姓名**学生学号***********专业班级 ******* 指导老师****完成日期****/**/**一、需求分析(1)编号为1-n的n个人按顺时针方向围成一圈.首先第1个人从1开始顺时针报数.报m的人(m 为正整数).令其出列。

然后再从他的下一个人开始,重新从1顺时针报数,报m的人,再令其出列。

约瑟夫环知识点总结

约瑟夫环知识点总结

约瑟夫环知识点总结1. 约瑟夫环的数学模型约瑟夫环可以用数学的方式进行建模和解决。

通常情况下,我们把约瑟夫环的问题理解为一个数学公式的求解。

假设n个士兵分别编号为1、2、3、...、n,m为出列的间隔数。

首先,我们可以得到第一个出列的士兵编号为(m-1)%n+1,例如当n=7,m=3时,第一个出列的士兵为(3-1)%7+1=3。

之后,每次出列后的编号变换规律为:下一个出列士兵的编号为前一个出列士兵编号加上m在n取模后的结果,并且再对n取模,即f(i)=f(i-1)+m)%n。

以上公式是解决约瑟夫环问题的核心,因为根据这个公式可以有效地计算出每一轮出列的士兵的编号。

然后我们只需要循环迭代这个公式,直到最后只有一个士兵为止,这个士兵的编号就是最后的结果。

2. 约瑟夫环的递归解法除了上述的数学模型,还可以使用递归的方法来解决约瑟夫环的问题。

递归是一种非常高效的解决问题的方法,适用于很多数学问题,包括约瑟夫环的计算。

递归方法的求解思路是:先假设已知了n-1个士兵的约瑟夫环问题的解f(n-1, m),那么我们要求的n个士兵的约瑟夫环的解f(n, m)可以通过以下方式推导得到。

首先,第一个出列的士兵编号为(m-1)%n+1,之后剩下的n-1个士兵重新排列成一个圆圈,编号重新从1到n-1。

将这n-1个士兵的解f(n-1, m)映射到n个士兵的解f(n, m)上,此时,再回到上述的数学模型进行计算,找到最终的结果。

递归的思路虽然清晰,但是在实际求解的过程中,由于递归的不断嵌套,计算量会非常庞大,不适合解决大规模的约瑟夫环问题。

3. 约瑟夫环的迭代解法在解决实际问题的时候,我们更多地使用迭代的方法来求解约瑟夫环的问题。

迭代的思路是从最简单的情况开始,然后不断迭代得到更加复杂的情况的解。

对于约瑟夫环问题,迭代的思路是逐步得出每一轮出列的士兵的编号并记录下来,直到剩下最后一个士兵为止。

通常情况下,我们会使用一个数组或者链表来保存每一轮出列的士兵的编号,最后得出最后一个士兵的编号。

约瑟夫环-数据结构

约瑟夫环-数据结构

数据结构期末试验报告学院:专业:学号:班级:姓名:2010.12.12 Joseph约瑟夫环上机实验报告实验名称:joseph约瑟夫环题目要求的约瑟夫环操作:编号是1,2,……,n的n个人按照顺时针方向围坐一圈,每个人只有一个密码(正整数)。

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

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

设计一个程序来求出出列顺序。

实验要求:1~)利用单向循环链表存储结构模拟此过程,按照出列的顺序输出各个人的编号。

2~)建立输入处理输入数据,输入m的初值,n ,输入每个人的密码,建立单循环链表。

3~)建立一个输出函数,将正确的输出序列4~)测试数据:m的初值为20,n=7 ,7个人的密码依次为3,1,7,2,4,7,4,首先m=6,则正确的输出是什么?实验过程:1.基本算法以及分析:本程序主要是以建立单循环链表的形式,建立起一个约瑟夫环,然后根据之前创立的结点,输入结点里的一些数据,如下typedef struct Node{int Index; 在当前环中所处的位置,即编号int Password; 在当前环中的所带的密码struct Node *next;}JosephuNode;程序有主函数开始,首先,提示输入创建约瑟夫环环数以及每个环上所带的密码。

然后,开始调用JosephuNode *Creat_Node函数,利用单循环链表建立起约瑟夫环,tail->next = head;就是将最后一个结点的后继指向头结点,函数结尾return head; 将约瑟夫环的头指针返回,并将它赋值head,然后主函数继续调用Josephu函数,通过讲head和Password 引入函数,以建立两个嵌套循环输出并实现如下功能:编号是1,2,……,n的n个人按照顺时针方向围坐一圈,每个人只有一个密码(正整数)。

数据结构 约瑟夫环

数据结构 约瑟夫环
背景介绍
弗拉维奥·约瑟夫(37-100)是第一世纪时的著名 弗拉维奥·约瑟夫(37-100)是第一世纪时的著名 (37 的犹太历史学家,也是军官及辩论家。 的犹太历史学家,也是军官及辩论家。 《犹太古史》(The Antiquities of the Jews): 犹太古史》 Jews): 记录了由圣经创世记至公元66年的犹太人历史, 66年的犹太人历史 记录了由圣经创世记至公元66年的犹太人历史, 以旧约圣经为蓝图以及古人的传说, 以旧约圣经为蓝图以及古人的传说,编写而成的 犹太巨著。由于当时的犹太人散居各地, 犹太巨著。由于当时的犹太人散居各地,此书成 为各地土生犹太人重要学习典籍, 为各地土生犹太人重要学习典籍,亦为当代神学 学者及历史学者所采用。 学者及历史学者所采用。
循环链表的创建图例
end a0 a1 a2 an-1
带表头结点的循环链表
end end (空表) 空表) a
0
a1
an-1 (非空表) 非空表)
பைடு நூலகம்
关于循环链表的剔除函数
我们先看一个图形实例图示 我们先看一个图形实例图示
♦例如 总数 n = 8 ♦剔除间隔m = 3 剔除间隔m
剔除函数
void kill(int n,int s,int m) { int i,j,k; node<t> *p,*q; p=end->link; for(i=1;i<s;i++) //寻找 结点 寻找s结点 寻找 p=p->link; for(j=1;j<n;j++)//剔除 个人 剔除n-1个人 剔除 { for(k=1;k<m-1;k++)/*毎 毎 数到第m个就踢出的间隔 个就踢出的间隔*/ 数到第 个就踢出的间隔 { p=p->link;

数据结构实验报告约瑟夫环

数据结构实验报告约瑟夫环

数据结构实验报告约瑟夫环约瑟夫环是一个古老而有趣的问题,也是数据结构中一个经典的应用。

它的故事发生在公元前1世纪,当时犹太人正面临罗马的入侵。

为了避免被俘虏,一群犹太士兵决定以一种特殊的方式自杀,而不是被罗马人俘虏。

他们围成一个圈,按照某个规则进行自杀,直到只剩下一个人为止。

这就是著名的约瑟夫环问题。

在这个问题中,我们有n个人,编号从1到n,围成一个圈。

按照一定的规则,从第一个人开始报数,每次报到m的人将被淘汰。

然后,从下一个人开始重新报数,如此循环,直到只剩下一个人为止。

这个问题的解决方法有很多,其中最常见的是使用链表数据结构。

我们可以将每个人表示为一个节点,节点之间通过指针连接,形成一个环形链表。

每次淘汰一个人后,只需要将指针跳过被淘汰的节点,重新连接链表。

为了更好地理解这个问题,我们可以通过一个简单的例子来演示。

假设有10个人,编号从1到10,每次报数到3的人将被淘汰。

首先,我们将这10个人表示为一个环形链表:1->2->3->4->5->6->7->8->9->10->1。

按照规则,第一次报数到3的人是3号,所以我们将3号节点从链表中删除:1->2->4->5->6->7->8->9->10->1。

接下来,从4号节点开始重新报数。

第二次报数到3的人是6号,所以我们再次将6号节点从链表中删除:1->2->4->5->7->8->9->10->1。

以此类推,直到只剩下一个人为止。

通过这个例子,我们可以看到约瑟夫环问题的解决方法非常简单直观。

使用链表数据结构,每次淘汰一个人后,只需要将指针跳过被淘汰的节点,重新连接链表。

这种方法的时间复杂度为O(n*m),其中n为人数,m为报数的次数。

除了链表,还有其他数据结构可以用来解决约瑟夫环问题。

约瑟夫环算法数据结构

约瑟夫环算法数据结构

约瑟夫环算法数据结构《约瑟夫环算法数据结构》想象一下这样一个场景,在一个充满欢乐氛围的校园里,有一群朝气蓬勃的学生。

我呢,就是其中一个对算法充满好奇的家伙。

这一天,我们的数学老师,一个戴着厚厚眼镜,头发有点稀疏但眼神中透着智慧光芒的中年人,要给我们讲一个超级有趣的数学游戏,这个游戏就和约瑟夫环算法有关。

老师站在讲台上,手里拿着粉笔,眼睛扫视着我们,脸上带着神秘的笑容。

他说:“同学们,今天我们来玩个特别的游戏。

”只见他在黑板上画了一个大大的圈,然后在圈里依次写上1到n这些数字,代表着n个同学。

老师接着说:“现在假设你们就是这些数字所代表的人,我们要进行一个淘汰游戏。

从数字1开始,按顺时针方向报数,每报到m的人就离开这个圈子,就像被淘汰出局一样,然后下一个人再从1开始报数,一直这样循环下去,直到最后只剩下一个人。

这个游戏的过程其实就反映了约瑟夫环算法哦。

”同学们开始交头接耳,有的跃跃欲试,有的则皱着眉头,感觉有点懵。

我心里想:“这听起来有点复杂呢,不过好像很有趣。

”我们开始玩这个游戏,我是数字3。

第一轮开始报数,我紧张地听着前面同学报数,就像等待命运审判一样。

“1,2,3”,当报到3的时候,我心里一凉,不过按照规则,我只能沮丧地离开圈子,走到教室后面。

我看着剩下的同学们继续报数,就像一个被抛弃的小兵。

从这个游戏中,我们可以看到约瑟夫环算法的数据结构就像是一个环形的队列。

每个同学就像是队列中的一个元素,在这个环形结构里,有顺序地进行报数操作。

每淘汰一个同学,就相当于从这个数据结构中移除一个元素。

这个过程中,位置的计算和元素的移动是关键。

如果从数据结构的角度来看,我们可以用数组或者链表来实现约瑟夫环算法。

就好比把同学们排成一排(数组)或者用链子把同学们串起来(链表),然后按照规则进行操作。

如果用数组的话,每次有人被淘汰,我们可能需要移动后面的元素来填补空缺,这就像同学们之间互相挪动位置,有点麻烦呢。

而链表就不一样了,链表中的节点可以很方便地删除,就像同学们可以轻松地从链子上解开,不需要挪动其他人的位置。

数据结构实验报告约瑟夫环

数据结构实验报告约瑟夫环

数据结构实验报告约瑟夫环约瑟夫环是一种经典的数学问题,它源于古代传说中的故事。

根据传说,约瑟夫是一位犹太历史学家,他和他的朋友们被罗马军队包围在一个洞穴里。

为了避免被俘虏,他们决定自杀,但是他们决定以一个特殊的方式来做。

他们围成一个环,从一个人开始,每隔一个人就杀死一个,直到只剩下一个人。

约瑟夫是最后一个幸存者。

这个问题可以用数据结构来解决,其中最常用的方法是使用循环链表。

循环链表是一种特殊的链表,它的最后一个节点指向第一个节点,形成一个环。

在解决约瑟夫环问题时,我们可以使用循环链表来模拟这个环。

首先,我们需要创建一个循环链表,并将所有的人依次添加到链表中。

然后,我们需要设置一个计数器,用来记录当前的位置。

接下来,我们需要遍历链表,每次遍历到计数器所指向的位置时,将该节点从链表中删除,并将计数器加一。

当计数器的值等于要删除的位置时,我们就将该节点删除,并将计数器重置为1。

重复这个过程,直到链表中只剩下一个节点为止。

通过使用循环链表,我们可以很方便地解决约瑟夫环问题。

这种方法的时间复杂度为O(n*m),其中n表示初始链表的长度,m表示要删除的位置。

由于每次删除一个节点后,链表的长度会减少,所以实际上的时间复杂度会小于O(n*m)。

除了使用循环链表,还可以使用数组来解决约瑟夫环问题。

我们可以创建一个长度为n的数组,然后将所有的人依次添加到数组中。

接下来,我们需要设置一个计数器,用来记录当前的位置。

然后,我们需要遍历数组,每次遍历到计数器所指向的位置时,将该人从数组中删除,并将计数器加一。

当计数器的值等于要删除的位置时,我们就将该人删除,并将计数器重置为1。

重复这个过程,直到数组中只剩下一个人为止。

与循环链表相比,使用数组解决约瑟夫环问题的方法更加简单。

但是,数组的长度是固定的,所以如果要解决的问题规模很大,可能会导致内存的浪费。

此外,数组的删除操作需要移动其他元素,所以时间复杂度较高。

综上所述,约瑟夫环问题是一个经典的数学问题,可以通过使用循环链表或数组来解决。

数据结构实验报告约瑟夫环

数据结构实验报告约瑟夫环

数据结构实验报告约瑟夫环约瑟夫环是一个经典的问题,涉及到数据结构中的循环链表。

在本次数据结构实验中,我们将学习如何使用循环链表来解决约瑟夫环问题。

约瑟夫环问题最早出现在古代,传说中的犹太历史学家约瑟夫斯·弗拉维奥(Josephus Flavius)在围攻耶路撒冷时,为了避免被罗马人俘虏,与其他39名犹太人躲进一个洞穴中。

他们决定宁愿自杀,也不愿被敌人俘虏。

于是,他们排成一个圆圈,从第一个人开始,每次数到第七个人,就将他杀死。

最后剩下的人将获得自由。

在这个问题中,我们需要实现一个循环链表,其中每个节点表示一个人。

我们可以使用一个整数来表示每个人的编号。

首先,我们需要创建一个循环链表,并将所有人的编号依次添加到链表中。

接下来,我们需要使用一个循环来模拟每次数到第七个人的过程。

我们可以使用一个指针来指向当前节点,然后将指针移动到下一个节点,直到数到第七个人为止。

一旦数到第七个人,我们就将该节点从链表中删除,并记录下该节点的编号。

然后,我们继续从下一个节点开始数数,直到只剩下一个节点为止。

在实现这个算法时,我们可以使用一个循环链表的数据结构来表示约瑟夫环。

循环链表是一种特殊的链表,其中最后一个节点的指针指向第一个节点。

这样,我们就可以实现循环遍历链表的功能。

在实验中,我们可以使用C语言来实现循环链表和约瑟夫环算法。

首先,我们需要定义一个节点结构体,其中包含一个整数字段用于存储编号,以及一个指针字段用于指向下一个节点。

然后,我们可以实现创建链表、添加节点、删除节点等基本操作。

接下来,我们可以编写一个函数来实现约瑟夫环算法。

该函数接受两个参数,分别是参与游戏的人数和每次数到第几个人。

在函数内部,我们可以创建一个循环链表,并将所有人的编号添加到链表中。

然后,我们可以使用一个循环来模拟每次数到第几个人的过程,直到只剩下一个节点为止。

在每次数到第几个人时,我们可以删除该节点,并记录下其编号。

最后,我们可以返回最后剩下的节点的编号。

数据结构~约瑟夫问题

数据结构~约瑟夫问题

#include <stdio.h>#include <stdlib.h>struct JEnode{char name[10];long number;char sex[10];int age;char class_[10];char health[10];struct JEnode *next;};typedef struct JEnode student;student *creatJEnode(int n){student *head,*ps,*tail;int i;head=tail=NULL;for(i=0; i<n; i++){ps=(student*)malloc(sizeof(student));scanf("%s",ps->name);scanf("%ld",&ps->number);scanf("%s",ps->sex);scanf("%d",&ps->age);scanf("%s",ps->class_);scanf("%s",ps->health);ps->next=NULL;if(i==0)head=tail=ps;else{tail->next=ps;tail=ps;}}tail->next=head;return head;}void JEcancel(student *head,int m){student *p,*q;int j=1;p=head;q=NULL;while(p->next!=p){if(j==m-1){q=p->next;printf("%s ",q->name);printf("%ld ",q->number);printf("%s ",q->sex);printf("%d ",q->age);printf("%s ",q->class_);printf("%s",q->health);printf("\n");free(q);p->next=q->next;//让p指向q的下一个,重新开始计数*j=0;//这是删除是的状态,故j=0}p=p->next;//p指针不断的往后移动j++;}q=p->next;printf("%s ",q->name);printf("%ld ",q->number);printf("%s ",q->sex);printf("%d ",q->age);printf("%s ",q->class_);printf("%s",q->health);printf("\n");free(q);}int main(void){student *head;int total,mark;scanf("%d",&total);scanf("%d",&mark);head=creatJEnode(total);//printf("\n");JEcancel(head,mark);return 0;}。

数据结构—约瑟夫环问题(循环单链表)

数据结构—约瑟夫环问题(循环单链表)

数据结构—约瑟夫环问题(循环单链表)n个数据元素构成⼀个环,从环中任意位置开始计数,计到m将该元素从表中取出,重复上述过程,直⾄表中只剩下⼀个元素。

解题思路:⽤⼀个⽆头结点的循环单链表来实现n个元素的存储。

循环单链表:尾指针指向头结点。

这样指针可以循环移动。

可以使⽤两个指针来操作,将指针q指向需要操作的结点上,指针p指向需要操作结点的前⼀个结点。

1 #include <stdio.h>2 #include <stdlib.h>3 #include <malloc.h>4 #include <math.h>5#define NULL 06 typedef struct LNode7 {8int num;///编号9struct LNode *next;10 } LNode, *Linklist;11 Linklist head,tail;12void Createlist(int n)///创建含有n个结点的单循环链表13 {14int i;15 Linklist p,q;16 head=(Linklist)malloc(sizeof(LNode));17 q=head;18 q->num=1;19for(i=2; i<=n; i++)20 {21 p=(Linklist)malloc(sizeof(LNode));22 p->num=i;23 q->next=p;24 q=p;25 }26 p->next=head;27 tail=p;///尾指针要指向头结点28 }29void Outlist(int k)30 {31int i;32 Linklist p,q;33 p = head;34for(i=1; i<k-1; i++)///循环k-2次35 {36 p = p->next;///指向需要操作元素的前⼀个指针37 }38 q = p->next;///指向需要操作元素的指针39while(q != p)40 {41 printf("%3d",q->num);42 p->next = q->next;///删除q所指向的元素43for(i=1; i<k; i++)///因为要经过已经删除的元素,所以需要多删除⼀次44 {45 p = p->next;46 }47 q = p->next;48 }49 printf("%3d\n",q->num);5051 }52int main()53 {54int k,n;55 printf("---------------约瑟夫环问题--------------\n");56 printf("\n请输⼊总⼈数和从第⼏个⼈开始报数n,k:\n");57 scanf("%d%d",&n,&k);58 Createlist(n);59 printf("\n出队的次序:\n");60 Outlist(k);61return0;62 }我看了⼀下我同学的做法,可以p直接使⽤尾指针,⽽q来⾃头指针,这样在遍历的时候,p指针⼀直会在q指针之前。

数据结构——约瑟夫环

数据结构——约瑟夫环

数据结构——约瑟夫环今⽇⼀⾔:谢谢你,成为我前进的理由。

——《⾔叶之庭》数据结构 —— 约瑟夫环这是⽤链表实现的,约瑟夫环的规则是:总数为N的同学围成⼀个圆环,并将这些同学从1开始编号,游戏开始时,约定好⼀个数字K,从1号同学开始轮着叫号,当叫到K号时,该同学淘汰,下⼀位同学从1开始重新叫号,只要叫到K号即淘汰,留下来的最后⼀位同学赢得游戏。

C语⾔实现/*********************************************************************************** 约瑟夫环* create: 2020年5⽉24⽇ 22点22分* author: LOS(⼩鱼)** *******************************************************************************/#include<stdio.h>#include<stdlib.h>/********************************************************************************** 链表需要********************************************************************************/typedef struct Elem{int value;struct Elem *prev,*next;}Elem;struct{Elem elems[200];int size;} Elems; // 全部的链表数据存储在这⾥(不销毁, 但会覆盖)// 定义链表结构typedef struct {struct Elem *first;struct Elem *last;int size;} LinkList;// 初始化链表void initLinkList( LinkList *list ){list->size = 0;}// 获取表长int getSizeL(LinkList *list){return list->size;}void addFirst(LinkList *list,Elem *elem){if( !getSizeL(list) ){list->first = elem;list->last = elem;}else {elem->next = list->first;list->last->next = elem;list->first->prev = elem;list->first = elem;}list->size++;}// 添加元素void addLast(LinkList *list,Elem *elem){if( !getSizeL(list) ){list->first = elem;list->last = elem;} else {elem->prev = list->last;elem->next = list->first;list->last->next = elem;list->first->prev = elem;list->last = elem;}list->size++;}Elem * getElem(LinkList *list, int index){int i ;Elem *elem;// 逐项访问if ( index > list->size/2 ){elem = list->last;for ( i = list->size-1 ; i >= index ; i-- ){if( i == index ){return elem;}elem = elem->prev;}} else {elem = list->first;for ( i = 0 ; i <= index ; i++ ){if( i == index ){return elem;}elem = elem->next;}}}// 移除元素void removeIndexL(LinkList *list, int index){ int i;Elem *elem = list->first;int flag = 0;for ( i = 0 ; i <= index ; i++ ){if( i == index ){elem->prev->next = elem->next;elem->next->prev = elem->prev;if( list->first == elem ){list->first = elem->next;}if( list->last == elem ){list->last = elem->prev;}flag = 1;}elem = elem->next;}if(!flag) printf("没能完成任务\n"); list->size--;}void removeElemL(LinkList *list, Elem *e){ int i;Elem *elem = list->first;int flag = 0;for ( i = 0 ; i < list->size ; i++ ){if( elem == e ){elem->prev->next = elem->next;elem->next->prev = elem->prev;list->first = elem->next;}if( list->last == elem ){list->last = elem->prev;}flag = 1;}elem = elem->next;}if(!flag) printf("没能完成任务\n");list->size--;}/********************************************************************************** 链表需要********************************************************************************/Elem *createElem( int value ){Elem *p = Elems.elems+Elems.size;p->value = value;Elems.size++;if( Elems.size == 200 ) Elems.size = 0; // 注意不能超过200,否则数据错误return p;}void main(){LinkList list;int n,k,i,count;printf("请输⼊参与游戏的总⼈数:");scanf("%d",&n);fflush(stdin);printf("请输⼊淘汰的间隔数:");scanf("%d",&k);fflush(stdin);initLinkList(&list);for ( i = 0 ; i < n ; i++ ){Elem *elem = createElem(i+1);addLast(&list,elem);}printf("游戏开始......\n");count = 0;while(list.size>1){count = (count+k-1)%list.size;printf("%d号同学被淘汰.\n",getElem(&list,count)->value);removeIndexL(&list,count);}printf("最后的赢家是 --> %d号同学!\n",st->value);}运⾏结果请输⼊参与游戏的总⼈数:10请输⼊淘汰的间隔数:3游戏开始......3号同学被淘汰.6号同学被淘汰.9号同学被淘汰.2号同学被淘汰.7号同学被淘汰.1号同学被淘汰.8号同学被淘汰.5号同学被淘汰.10号同学被淘汰.最后的赢家是--> 4号同学!--------------------------------Process exited after 2.205 seconds with return value 27请按任意键继续. . .。

数据结构实验报告一-约瑟夫环问题

数据结构实验报告一-约瑟夫环问题

实验1约瑟夫环问题1.需求分析(1)输入的形式和输入值的范围:每一次输入的值为两个正整数,中间用逗号隔开。

若分别设为n,m,则输入格式为:“n,m”。

不对非法输入做处理,即假设输入都是合法的。

(2)输出的形式:输出格式1:在字符界面上输出这n个数的输出序列输出格式2:将这n个数的输出序列写入到文件中(3)程序所能达到的功能:对于输入的约瑟夫环长度n和间隔m,输出约瑟夫环的出列顺序。

(4)测试数据:包括正确的输入及其输出结果和含有错误的输入及其输出结果。

正确:输入:10,3输出:3 6 9 2 7 1 8 5 10 4输入:41,3输出:3 6 9 12 15 18 21 24 27 30 33 36 39 1 5 10 14 19 23 28 32 37 41 7 13 20 2634 40 8 17 29 38 11 25 2 22 4 35 16 31错误:输入:10 3输出:6 8 7 1 3 4 2 9 5 102.概要设计(1)抽象数据类型的定义:为实现上述程序的功能,可以用整数存储用户的输入。

并将用户输入的值存储于线性表中。

线性表ADT定义如下:ADT list数据对象:整形数据关系:线性关系,即<ai,ai+1>(0≤a<n)。

基本操作:bool remove(int &elem)//移除一个元素,被移除的元素赋给elem//如果操作成功,返回true,否则返回falsebool isEmpty()//判断数组的元素是否清空,空返回true,否则返回falsebool setPos(int place)//设置当前元素的位置,设置成功返回true,否则返回falseint getLength()//获取数组的实际长度(2)算法的基本思想:约瑟夫环问题中的数据是人所在的位置,而这种数据是存在“第一元素、最后元素”,并且存在“唯一的前驱和后继的”,符合线性表的特点。

约瑟夫环问题的两种解法(循环链表和公式法)

约瑟夫环问题的两种解法(循环链表和公式法)

约瑟夫环问题的两种解法(循环链表和公式法)问题描述这⾥是数据结构课堂上的描述: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),显然,这不是⼀个好的算法。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

约瑟夫环问题实验报告
本实验的目的是进一步理解线性表的逻辑结构和存储结构,进一步提高使用理论知识指导解决实际问题的能力。

一、问题描述
设编号为1,2,···,n的n个人围坐一圈,约定编号为m(1≤m≤n)的人从1开始报数,数到k的那个人出列,他的下一位又从1开始报数,数到k的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。

二、数据结构设计
①由于当某个人退出圆圈后,报数的工作要从下一个人开始继续,剩下的人仍要是围成一个圆圈,可以使用循环表;由于退出圆圈的工作对应着表中结点的删除操作,对于这种删除操作频繁的情况,应该选用效率较高的链表结构;为了程序指针每一次都指向一个具体的代表一个人的结点而不需要进行判断,链表不带表头结点。

所以,对于所有人围成的圆圈所对对应的数据结构采用一个不带头结点的循环链表来描述。

设头指针为p,并根据具体情况移动
可以采用数据类型定义:
Typedef struct node
{
int number;
struct node *next;
}Lnode,*Linklist;
②为了记录退出的人的先后顺序,采用一个顺序表进行存储,程序结束后再输入依次退出的人的编号顺序。

由于只记录各个结点的number值就可以,所以定义一个整型一维数组。

如“int quite[N];”N为一个根据实际问题定义的一个足够大的整数。

三、功能函数设计
根据上述分析,该算法可以由3个功能函数实现。

Main()用做数据的输入和函数的调用,Init()做链表的初始化工作,使用Josephus()做删除结点和保存输出顺序的工作,OutRing()完成序列的输出工作。

1.建立单循环链表函数 LinkList InitRingList(int n);
2.产生Josephus顺序函数 void Josephus(LinkList L,int n,int k,int m,int quit[N])
3.输出顺序表void Print(int n,int quit[N])
四、界面设计
本程序的界面力求简洁、友好,每一步需要用户操作以及每一次用户操作产生的调度结果都以中文的形式显示在屏幕上,使用户对要做什么和已经做了什么一目了然,文字表达精炼、准确。

五、编码实现
//#include "stdafx.h"
#include<iostream.h>
using namespace std;
#define N 34
typedef struct Node
{
int data;
struct Node *next;
}Lnode,*LinkList;
LinkList InitRingList(int n) //尾插法建立单循环链表{
Lnode *L,*r,*s;
L=new Lnode; //不带头结点
r=L;
for(int i=1;i<n;i++)
{
s=new Lnode;
r->data=i;
r->next=s;
r=s;
}
r->data=n;
r->next=L; //链表首尾相连
L=r; //L指向循环链表的尾结点
return L;
}
void Josephus(LinkList L,int n,int k,int m,int quit[N]) {
int i,j;
Lnode *p,*q;
p=L;
for(int r=1;r<m;r++)
p=p->next;
for(i=0;i<n;i++)
{
for(j=1;j<=k-1;j++)
p=p->next;
q=p->next;
p->next=q->next;
quit[i]=q->data;
delete q;
}
}
void Print(int n,int quit[N])
{
int i;
for(i=0;i<n;i++)
cout<<quit[i]<<" ";
cout<<endl;
}
int main(int argc, char* argv[])
{
LinkList L;
int n;
int k;
int m;
cout<<"请输入围坐一圈的人数n的值:"<<endl;
cin>>n;
L=InitRingList(n);
int quit[N];
cout<<"约定从编号为m的值开始数,请输入m的值:"<<endl;
cin>>m;
while(m>n||m<1)
{
cout<<"输入错误,请重新输入:"<<endl;
cin>>m;
}
cout<<"要求数到k的人出列,请输入k的值:"<<endl;
cin>>k;
cout<<"顺序为:";
Josephus(L,n,k,m,quit);
Print(n,quit);
return 0;
}
六、运行与测试
①当n的初始值为7,k的值为5,m的值为1时,正确的出列顺序为:5、
3、2、
4、7、1、6,经程序运行测试,结果如下:
可知程序运行正确。

②程序的容错性测试,当输入m的值不符合问题约定时,应有错误提示给用户,指导用户正确输入,并做出相应处理,保证程序运行。

测试如下:
七、实验完成后的思考
数据结构是一门比较抽象的课程,但是也是一门最基础的课程学的过程。

在现实生活的应用也非常广泛通过设计该实验让我更加深刻的掌握了掌握了,有关链表的知识,同时也认识到了自己在平时学习当中的盲点,通过这次实验发现了自己在数据结构这门功课上存在严重的不足。

链表中的指针理解不够,运用不够熟练,常常出现一些莫名其妙的问题,调试费时太多。

今后一定会多编程,多思索。

在以后的学习过程中还需要不断的完善学习,希望能把数据结构这门课学习的更加深入,更加透彻。

最后,非常感谢老师在实验的过程所提供的帮助和指导。

实验人:陈京九
实验完成日期:2014年10月5日
实验报告提交日期:2014年10月9日。

相关文档
最新文档