数据结构Josephus问题
三种存储结构(顺序表,链表,静态链表)求解josuphu问题的实验报告
实验报告:使用三种存储结构(顺序表、链表、静态链表)求解Josephus问题一、实验目的掌握顺序表、链表和静态链表的基本操作和实现方法。
学习如何使用不同的存储结构解决同一问题,并分析其性能差异。
通过求解Josephus问题,加深对数据结构在实际问题中应用的理解。
二、实验内容问题描述:Josephus问题是著名的理论问题。
在罗马人占领乔塔帕特后,n个犹太人与他们的妻子和孩子被一个圈子所包围,圈中第一个人从1开始报数,每数到m的那个人就被杀死,然后再由他的下一个人从1开始重新报数,直到剩下最后一个人为止,那个人就被称为Josephus。
本实验要求使用顺序表、链表和静态链表三种存储结构求解Josephus问题。
顺序表求解Josephus问题:使用数组作为顺序表存储结构,通过循环遍历数组实现报数和杀人过程。
当杀死某个人时,将其后的人依次向前移动填补空位。
重复此过程直到只剩下一个人为止。
链表求解Josephus问题:使用链表作为存储结构,通过链表的遍历实现报数和杀人过程。
当杀死某个人时,将其从链表中删除。
重复此过程直到链表中只剩下一个节点为止。
静态链表求解Josephus问题:使用静态链表作为存储结构,通过数组模拟链表操作。
在静态链表中,每个节点包含数据域和游标域。
通过游标域实现节点间的链接关系。
通过遍历静态链表实现报数和杀人过程,当杀死某个人时,修改其前后节点的链接关系以删除该节点。
重复此过程直到静态链表中只剩下一个节点为止。
三、实验结果与分析实验结果:使用顺序表求解Josephus问题时,时间复杂度较高,因为每次杀人后都需要移动大量元素来填补空位。
空间复杂度较低,只需一个大小为n的数组。
使用链表求解Josephus问题时,时间复杂度较低,因为删除节点时只需修改相邻节点的指针。
空间复杂度与顺序表相当,但需要额外的指针空间来存储节点间的链接关系。
使用静态链表求解Josephus问题时,时间复杂度和空间复杂度与链表相似。
约瑟夫环问题(Josephus)源代码讲解
原题:用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至全部输出。
写出C程序。
(约瑟夫环问题 Josephus)提示:由于当某个人退出圆圈后,报数的工作要从下一个人开始继续,剩下的人仍然是围成一个圆圈的,可以使用循环表,由于退出圆圈的工作对应着表中结点的删除操作,对于这种删除操作频繁的情况,选用效率较高的链表结构,为了程序指针每一次都指向一个具体的代表一个人的结点而不需要判断,链表不带头结点。
所以,对于所有人围成的圆圈所对应的数据结构采用一个不带头结点的循环链表来描述。
设头指针为p,并根据具体情况移动。
为了记录退出的人的先后顺序,采用一个顺序表进行存储。
程序结束后再输出依次退出的人的编号顺序。
由于只记录各个结点的number值就可以,所以定义一个整型一维数组。
如:int quit[n];n为一个根据实际问题定义的一个足够大的整数。
代码:/******************************************************************** created: 2006/06/14 filename: C:\Documents and Settings\Administrator\桌面\tmpp\josephus.c file path: C:\Documents and Settings\Administrator\桌面\tmpp file base: josephus file ext: c author: A.TNG version: 0.0.1 purpose: 实现 Josephus 环问题用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至全部输出。
写出C程序。
(约瑟夫环问题 Josephus)*********************************************************************/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <malloc.h> /* 结构体和函数声明 */ typedef struct _node_t { int n_num; struct _node_t *next; } node_t; node_t *node_t_create(int n); node_t *node_t_get(node_t **pn, int m); /* 功能函数实现 */ /* * name: node_t_create * params: * n [in] 输入要构造的链表的个数 * return: * 返回构造成功的环形单向链表指针 * notes: * 构造节点数量为 n 的环形单向链表* * author: A.TNG 2006/06/14 17:56 */ node_t * node_t_create(int n) { node_t *p_ret = NULL; if (0 != n) { int n_idx = 1; node_t *p_node = NULL; /* 构造 n 个 node_t */p_node = (node_t *) malloc(n * sizeof(node_t)); if (NULL == p_node) return NULL; else memset(p_node, 0, n * sizeof(node_t)); /* 内存空间申请成功 */ p_ret = p_node; for (; n_idx < n; n_idx++) { p_node->n_num = n_idx; p_node->next = p_node + 1;p_node = p_node->next; } p_node->n_num = n;p_node->next = p_ret; } return p_ret; } /* * name: main * params: * none * return: * int * notes: * main function * * author: A.TNG 2006/06/14 18:11 */ int main() { int n, m; node_t *p_list, *p_iter; n = 20; m = 6; /* 构造环形单向链表 */ p_list =node_t_create(n); /* Josephus 循环取数 */ p_iter = p_list; m %= n; while (p_iter !=p_iter->next) { int i = 1; /* 取到第 m-1 个节点 */ for (; i < m - 1; i++) { p_iter =p_iter->next; } /* 输出第 m 个节点的值 */ printf("%d\n", p_iter->next->n_num); /* 从链表中删除第 m 个节点 */ p_iter->next = p_iter->next->next; p_iter = p_iter->next; } printf("%d\n", p_iter->n_num); /* 释放申请的空间 */ free(p_list); system("PAUSE"); }。
数据结构与算法分析(1)——约瑟夫问题
数据结构与算法分析(1)——约瑟夫问题0 问题描述 据说著名犹太历史学家 Josephus有过以下的故事:在罗马⼈占领乔塔帕特后,39 个犹太⼈与Josephus及他的朋友躲到⼀个洞中,39个犹太⼈决定宁愿死也不要被敌⼈抓到,于是决定了⼀个⾃杀⽅式,41个⼈排成⼀个圆圈,由第1个⼈开始报数,每报数到第3⼈该⼈就必须⾃杀,然后再由下⼀个重新报数,直到所有⼈都⾃杀⾝亡为⽌。
然⽽Josephus 和他的朋友并不想遵从。
⾸先从⼀个⼈开始,越过k-2个⼈(因为第⼀个⼈已经被越过),并杀掉第k个⼈。
接着,再越过k-1个⼈,并杀掉第k个⼈。
这个过程沿着圆圈⼀直进⾏,直到最终只剩下⼀个⼈留下,这个⼈就可以继续活着。
问题是,给定了和,⼀开始要站在什么地⽅才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与⾃⼰安排在第16个与第31个位置,于是逃过了这场死亡游戏。
[1] 简单地说就是n个⼈围成⼀个圈,假设编号为0~n-1,报数范围为1~m。
从第0个⼈开始报数,每报到m,这个⼈就出局。
接着下⼀个⼈从1开始重新报数...直到剩下最后⼀个⼈。
1 问题解法 该问题常⽤解法有链表法和数组法,其他的⽐如公式法和递归法以后补充。
个⼈觉得链表法最容易理解,可能是先⼊为主的⼼理,嘿嘿嘿,下⾯就简单说⼀下。
1.1 链表法 ⾸先建⽴长度为n的循环链表,然后头结点开始报数,每第m个数删除⼀个结点,直到只剩下⼀个结点。
#include <iostream>using namespace std;struct ListNode{int val;struct ListNode* next;};/******创建循环链表******/ListNode* creatCirListNode(int n){//创建头结点ListNode *head,*node,*newnode;node = new ListNode;node->val = 0;node->next = NULL;head = node;//创建链表for (int i = 1; i < n; i++){newnode = new ListNode;newnode->val = i;node->next = newnode;node = newnode;}//将最后⼀个结点指向头结点,形成循环链表node->next = head;return head;}/******约瑟夫问题求解******/int josephSolution(ListNode* head,int m){if (NULL == head){return -1;}ListNode* pNode; //⽤来遍历结点pNode = head;while (pNode->next != pNode) //循环终⽌条件是只剩下⼀个结点{for (int i = 0; i < m-1; i++) //报数{pNode = pNode->next;}cout << pNode->next->val << "->";pNode->next = pNode->next->next; //删除链表结点}return pNode->val;}int main(){int n = 41;int m = 3;int result;ListNode* pHead;pHead = creatCirListNode(n);result = josephSolution(pHead, m);cout << result << endl;system("pause");return0;} 运⾏结果:1.2 数组法 数组法的关键是使⽤求余的⽅法循环遍历数组i=(i+1)%n,其中i是数组下标即每个⼈的标号,n是总⼈数。
约瑟夫环数据结构实验
实验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的人,再令其出列。
约瑟夫(Josephus)问题与二进制数
约瑟夫(Josephus )问题与二进制数(2013年8月24日整理)一些人乘船远行,忽然遭遇到大风浪,船舱漏了水,很快就可能沉没.船上只有一只救生圈,谁都想利用它逃生.在争执得不可开交之时,约瑟夫提出一个“公平”的办法:大家站成一个圈,从某人开始,1、2、1、2、1、2、… 地报数.凡报到2的人退出圈外——他失去了拥有救生圈逃生的机会,直到剩下一人.这人是“天意”赋予他生机,救生圈归他使用.依照这种“公平”的办法,约瑟夫从劫难中生还.试问他是站在什么位置上的呢?比如说,船上有11人,他该在什么位置?船上20人,他又该在什么位置?推而广之,船上有2n 人或2n +1人,又该如何呢?下面做点儿细致的研究.假设船上有n 个人,从开始报数的人起,依序编号为1、2、3、…、n ,幸存者所小的位置号记为()f n ;显然,(1)1f =、(2)1f =、(3)3f =.当有2n 个人,报数一圈后,淘汰掉2、4、6、…、2n 号位的人,剩下1、3、5、…、21n -号位的人共n 个,又从1号开始报数,这些人的第()f n 个是幸存者,但这个人在原先的位置上是第2()1f n -号,所以(2)()1f n f n =-;(比如:(4)2(2)12111f f =-=⨯-=,(6)2(3)15f f =-=). 当有21n +个人时,报数一圈后,淘汰掉2、4、6、…、2n 、1.号位的人,(这里为何去掉1号?此仍技巧一...),剩下3、5、7、…、21n +号位的人,共n 个;这时,从3开始报数,这些人中的第()f n 个是幸存者,但这个原先的位置是第2()1f n +,所以(21)()1f n f n +=+;(比如: (5)2(2)13f f =+=,(11)2(5)17f f =+=).令()()g n n f n =-,(这里为何这样变换?此仍技巧..二.). 由(*)得:(2)2()1(21)2(), (1)0g n g n g n g n g =+⎧⎨+==⎩(**).考虑二进制...表示,(这里为何考虑二进制数?此仍技巧..三.).对n 与()g n 都用二进制表示,因为二进制数有一些与十进制数类似的运算性质.比如,对任何自然数n ,10n 可以把n 的十进制表示的每位向左移动一位,然后在个位数上添一个0;101n +可以把n 的十进制表示的每一位左移一位,然后在个位数上添一个1.若用二进制数表示,则由(**)式可知(2)g n 是()g n 左移一位后在个位数上添1,而(21)g n +是()g n 左移一位后在个位上添0;从而,由(1)0g =可得()g n 是用二进制数表示n 的数中把0换成1,而把1换成0所得的数.这一结论可用第二.. (1)当1n =时,结论显然成立;(2)假设n k ≤(*)k N ∈时,结论成立,即对任一不大于k 的正整数122()m p a a a = ,其中有{0, 1}i a ∈,1, 2, , i m = ,都有122()()m g p a a a = ,这里1i i a a +=,即当1i a =,则0i a =,当0i a =,则1i a =;当1n k =+时,分两种情形:①若k 是奇数,即21k p =-,则1222(0)m n p a a a == , 1212222()(2)2()1(0)(1)(1)m m g n g p g p a a a a a a ==+=+= ;②若k 是偶数,即2k p =,则122212221(0)(1)(1)m m n p a a a a a a =+=+= , 122()(21)2()(0)m g n g p g p a a a =+== ;这说明,当1n k =+时,结论也成立;根据(1)和(2 下面继续探究()f n 的表达式.根据上述分析可知:若n 是k 位的二进制数,即122k k n -≤<,(***),则()n g n +是每位均为1的k 位二进制数,即1()12221k k n g n -+=+++=- ,故()()221k f n n g n n =-=-+;而由(***)式,可得:21log k n k -≤<,所以21[log ]k n -=,(这就是要求的通项公式)从这个问题可见二进制的作用不可小视之.下面再举一例,注意分析过程. 题目:对怎样的正整数n ,方程[][2][4][8]x x x x n +++=(☆)中的x 有解? 解答:设[]x x r =+,把r 用二进制数表示:312123223(0. )222a a a r a a a ==+++ ,{0, 1}i a ∈, 则有1[2]2[]x x a =+;12212[4]4[]()4[]2x x a a x a a =+=++;1232123[8]8[]()8[]42x x a a a x a a a =+=+++; 所以123[][2][4][8]15[]73x x x x x a a a +++=+++;令12373t a a a =++,因为1a 、2a 、3a {0, 1}∈,所以t 只能取到0、1、3、4、7、8、10、11这8个值,从而当且仅当n 被15除余数为0、1、3、4、7、8、10或11时,方程(☆)才有解.比如,13579n =时有解,因为135********=⨯+,从而905.375905.5x ≤<,所以4t =,即231a a ==,[]905x =,于是有44211905(0.011)9054816ax a =+=++++ ,有无穷多个解.但是,98765t=,不适合.n=时无解,这是因为987651565845=⨯+,即5。
数据结构经典题(一)Josephus(约瑟夫)问题
Josephus(约瑟夫)问题有n个人围成一个圈,从第1个人开始报数,数到第m个人,让他出局;然后从出局的下一个人重新开始报数,数到第m个人,再让他出局,……,如此反复直到剩下一个人,问此人编号为几?或:有n个人围成一个圈,从第k个人开始报数,数到第m个人,让他出局;然后从出局的下一个人重新开始报数,数到第m个人,再让他出局,……,如此反复直到所有人出列,由此产生一个出队编号的序列。
1、数组解法#include<iostream>#include<stdlib.h>using namespace std;const int n=11, m=3;int main(){int a[n],p=0;int i,k=0,number=0;for(i=0; i<n; i++) a[i]=i+1;while(number<n-1) //number表示出去的人数{ if(a[p]!=0) //p指向正要报数的人{ k++; //k为1,2,3...报数if(k==m) //报到m时,a[p]出去{ a[p]=0; k=0; number++; }}p=(p+1) % n; //下一个人}for(i=0; i<n; i++)if(a[i]!=0){ cout<<"最后一个获胜者的编号是:"<<i+1<<endl; break; }system("pause");}其中while循环也可改为:while(number<n-1) //number表示出去的人数{while(a[p]==0) p=(p+1) % n; //找到下一个报数的人k++; //k为1,2,3...报数if(k==m) //报到m时,a[p]出去{ a[p]=0; k=0; number++; }p=(p+1) % n;}2、链表解法#include<iostream>#include<stdlib.h>using namespace std;const int n=11, m=3;struct node{ int no;node *next;};int main(){int k=0;node *p,*q,*r;p=q=new node; //创建第一个节点p->no=1;for(int i=2; i<=n; i++) //建立链表{ r=new node;r->no=i;q->next=r;q=r;}q->next=p; //构成一个"环"q=p;while(q->next!=q){ k++; //k为1,2,3...报数if(k==m) //报到m时,删除q所指结点{ p->next=q->next;delete q;q=p->next;k=0;}else{ p=q; q=q->next; }}cout<<"最后一个获胜者的编号是:"<<q->no<<endl; system("pause");}其中while循环也可改为:while(q->next!=q){ for(int i=1; i<m; i++) //直接找到报m的人{ p=q; q=q->next; }p->next=q->next;delete q;q=p->next;}。
约瑟夫问题大全
“约瑟夫”问题及若干变种林厚从例1、约瑟夫问题(Josephus)[问题描述]M只猴子要选大王,选举办法如下:所有猴子按1…M编号围坐一圈,从第1号开始按顺序1,2,…,N报数,凡报到N的猴子退出到圈外,再从下一个猴子开始继续1~ N报数,如此循环,直到圈内只剩下一只猴子时,这只猴子就是大王。
M和N由键盘输入,1≤N,M≤10000,打印出最后剩下的那只猴子的编号。
例如,输入8 3,输出:7。
[问题分析1]这个例题是由古罗马著名史学家Josephus提出的问题演变而来的,所以通常称为Josephus(约瑟夫)问题。
在确定程序设计方法之前首先来考虑如何组织数据,由于要记录m只猴子的状态,可利用含m 个元素的数组monkey来实现。
利用元素下标代表猴子的编号,元素的值表示猴子的状态,用monkey[k]=1表示第k只猴子仍在圈中,monkey[k]=0则表示第k只猴子已经出圈。
程序采用模拟选举过程的方法,设变量count表示计数器,开始报数前将count置为0,设变量current表示当前报数的猴子编号,初始时也置为0,设变量out记录出圈猴子数,初始时也置为0。
每次报数都把monkey[current]的值加到count上,这样做的好处是直接避开了已出圈的猴子(因为它们对应的monkey[current]值为0),当count=n时,就对当前报数的猴子作出圈处理,即:monkey[current]:=0,count:=0,out:=out+1。
然后继续往下报数,直到圈中只剩一只猴子为止(即out=m-1)。
参考程序如下:program josephus1a {模拟法,用数组下标表示猴子的编号}const maxm=10000;var m,n,count,current,out,i:integer;monkey:array [1..maxm] of integer;beginwrite('Input m,n:');readln(m,n);for i:=1 to m do monkey[i]:=1;out:=0; count:=0; current:=0;while out<m-1 dobeginwhile count<n dobeginif current<m then current:=current+1 else current:=1;count:=count+monkey[current];end;monkey[current]:=0; out:=out+1; count:=0end;for i:=1 to m doif monkey[i]=1 then writeln('The monkey king is no.',i);readlnend.[运行结果]下划线表示输入Input m,n:8 3The monkey king is no.7 {时间:0秒}Input m,n:10000 1987The monkey king is no.8544 {时间:3秒}[反思]时间复杂度很大O(M*N),对于极限数据会超时。
josephus问题的算法(转载)
josephus问题的算法(转载)Josephus 问题:⼀群⼩孩围成⼀个圈,任意假定⼀个数 m,从第⼀个⼩孩起,顺时针⽅向数,每数到第 m 个⼩孩时,该⼩孩便离开。
⼩孩不断离开,圈⼦不断缩⼩,最后剩下的⼀个⼩孩便是胜利者。
究竟胜利的是第⼏个⼩孩呢?案例分析:解答这个问题,⾸先要定义⼀个数组,其元素个数就是⼩孩个数。
必须预先设置⼀个⼩孩个数常量,以便定义⼀个数组。
对每个⼩孩赋以⼀个序号作为⼩孩的标志。
由于数组是局部作⽤域的,⼀旦分配之后,就删不去,得等到作⽤域结束才会⾃动抹去,所以当⼩孩离开时,只能修改该数组元素值来表⽰⼩孩的离开。
数组是线性排列的,⼩孩是围成圈的,⽤数组表⽰⼩孩围成的圈,要有⼀种从数组尾部跳到数组头部的技巧,这就是“加1取模”。
当数到数组尾的时候,下⼀个数组下标值可以算得为0,从⽽回到数组⾸以继续整个过程。
程序如下:#include "stdafx.h"#include<iostream>#include<iomanip>using namespace std;int _tmain(int argc, _TCHAR* argv[]){//建⽴⼩孩数组const int num = 10; //⼩孩个数int interval; //每次数 interval 个⼩孩,便让该⼩孩离开int a[num]; //⼩孩数组//给⼩孩编号for(int i=0; i<num; i++) //⼩孩的编号只与⼩孩的个数有关a[i]=i+1;//输⼊⼩孩间隔 intervalcout<<"please input the interval:";cin>>interval;//将全体参加的⼩孩输⼊for(int i=0; i<num; i++) //顺序输出开始时的⼩孩编号cout<<a[i]<<",";cout<<endl;int k=1; //表⽰处理第 k 个离开的⼩孩int i=-1; //数组下标(下⼀个值 0 就是第⼀个⼩孩的下标)//处理获胜前的⼩孩while(true){//在圈中数 interval 个⼩孩for(int j=0; j<interval; ){i=(i+1) % num; //对下标加 1 取模(使得最后和⼀个⼩孩的下⼀个是第⼀个⼩孩)if(a[i] != 0) //如果该⼩孩在圈中,则承认该数有效j++;}if(k == num)break; //该⼩孩是最后的胜利者cout<<a[i]<<","; //输出离开的⼩孩编号a[i] = 0; //表⽰该⼩孩已经离开k++; //准备处理下⼀个圈中的⼩孩}//break 语句跳转到此cout<<endl<<"No."<<a[i]<<"boy's won."<<endl;return (0);}原⽂地址:《Visual C++ 编程从基础到应⽤》第四章末尾案例。
数据结构joseph课程设计
数据结构joseph课程设计一、课程目标知识目标:1. 学生能理解约瑟夫问题(Josephus problem)的背景和数学原理,掌握其与数据结构中循环链表的关系。
2. 学生能够掌握循环链表的基本操作,包括节点的插入、删除以及遍历。
3. 学生能够运用所学的循环链表知识解决约瑟夫问题,并理解其算法的效率。
技能目标:1. 学生能够运用编程语言(如C/C++/Java等)实现循环链表,并完成相应的约瑟夫问题求解程序。
2. 学生通过实际操作循环链表,提高逻辑思维能力和编程实践能力。
3. 学生能够通过分析、讨论和解决问题,培养团队协作能力和问题解决能力。
情感态度价值观目标:1. 学生通过解决实际问题,增强对数据结构学习的兴趣和热情,形成积极向上的学习态度。
2. 学生在团队协作中学会尊重他人,培养良好的沟通能力和合作精神。
3. 学生通过探究和解决约瑟夫问题,体会数学和计算机科学的实际应用价值,增强对科学的敬畏之心。
课程性质:本课程设计属于数据结构学科范畴,以实践操作和问题解决为核心,强调理论与实践相结合。
学生特点:考虑到学生已具备一定的编程基础和逻辑思维能力,课程设计将注重培养学生的实践能力、团队协作能力以及创新意识。
教学要求:教师应关注学生的个体差异,因材施教,引导学生通过自主探究、合作学习等方式达到课程目标。
在教学过程中,注重过程评价和结果评价相结合,全面评估学生的学习成果。
二、教学内容本节教学内容围绕数据结构中的循环链表及其应用——约瑟夫问题展开,具体安排如下:1. 循环链表基础知识回顾:- 循环链表的定义与特点- 循环链表的节点结构- 循环链表与普通链表的区别2. 循环链表的操作:- 节点的插入与删除- 循环链表的遍历- 循环链表的应用场景3. 约瑟夫问题介绍:- 约瑟夫问题的背景和数学原理- 约瑟夫问题与循环链表的关系4. 约瑟夫问题求解:- 算法设计思路- 编程实现步骤- 算法效率分析5. 实践环节:- 编写循环链表的基本操作函数- 编写求解约瑟夫问题的程序- 调试与优化程序6. 教学案例分析:- 结合实际案例,讲解循环链表在解决约瑟夫问题中的应用- 分析案例中的算法优化方法教学内容根据课本相应章节进行组织,确保学生能够在掌握循环链表基础知识的基础上,学会解决实际问题。
约瑟夫(Josephus)问题与二进制数
约瑟夫(Josephus )问题与二进制数(2013年8月24日整理)一些人乘船远行,忽然遭遇到大风浪,船舱漏了水,很快就可能沉没.船上只有一只救生圈,谁都想利用它逃生.在争执得不可开交之时,约瑟夫提出一个“公平”的办法:大家站成一个圈,从某人开始,1、2、1、2、1、2、… 地报数.凡报到2的人退出圈外——他失去了拥有救生圈逃生的机会,直到剩下一人.这人是“天意”赋予他生机,救生圈归他使用.依照这种“公平”的办法,约瑟夫从劫难中生还.试问他是站在什么位置上的呢?比如说,船上有11人,他该在什么位置?船上20人,他又该在什么位置?推而广之,船上有2n 人或2n +1人,又该如何呢?下面做点儿细致的研究.假设船上有n 个人,从开始报数的人起,依序编号为1、2、3、…、n ,幸存者所小的位置号记为()f n ;显然,(1)1f =、(2)1f =、(3)3f =.当有2n 个人,报数一圈后,淘汰掉2、4、6、…、2n 号位的人,剩下1、3、5、…、21n -号位的人共n 个,又从1号开始报数,这些人的第()f n 个是幸存者,但这个人在原先的位置上是第2()1f n -号,所以(2)()1f n f n =-;(比如:(4)2(2)12111f f =-=⨯-=,(6)2(3)15f f =-=). 当有21n +个人时,报数一圈后,淘汰掉2、4、6、…、2n 、1.号位的人,(这里为何去掉1号?此仍技巧一...),剩下3、5、7、…、21n +号位的人,共n 个;这时,从3开始报数,这些人中的第()f n 个是幸存者,但这个原先的位置是第2()1f n +,所以(21)()1f n f n +=+;(比如: (5)2(2)13f f =+=,(11)2(5)17f f =+=).令()()g n n f n =-,(这里为何这样变换?此仍技巧..二.). 由(*)得:(2)2()1(21)2(), (1)0g n g n g n g n g =+⎧⎨+==⎩(**).考虑二进制...表示,(这里为何考虑二进制数?此仍技巧..三.).对n 与()g n 都用二进制表示,因为二进制数有一些与十进制数类似的运算性质.比如,对任何自然数n ,10n 可以把n 的十进制表示的每位向左移动一位,然后在个位数上添一个0;101n +可以把n 的十进制表示的每一位左移一位,然后在个位数上添一个1.若用二进制数表示,则由(**)式可知(2)g n 是()g n 左移一位后在个位数上添1,而(21)g n +是()g n 左移一位后在个位上添0;从而,由(1)0g =可得()g n 是用二进制数表示n 的数中把0换成1,而把1换成0所得的数.这一结论可用第二.. (1)当1n =时,结论显然成立;(2)假设n k ≤(*)k N ∈时,结论成立,即对任一不大于k 的正整数122()m p a a a = ,其中有{0, 1}i a ∈,1, 2, , i m = ,都有122()()m g p a a a = ,这里1i i a a +=,即当1i a =,则0i a =,当0i a =,则1i a =;当1n k =+时,分两种情形:①若k 是奇数,即21k p =-,则1222(0)m n p a a a == , 1212222()(2)2()1(0)(1)(1)m m g n g p g p a a a a a a ==+=+= ;②若k 是偶数,即2k p =,则122212221(0)(1)(1)m m n p a a a a a a =+=+= , 122()(21)2()(0)m g n g p g p a a a =+== ;这说明,当1n k =+时,结论也成立;根据(1)和(2 下面继续探究()f n 的表达式.根据上述分析可知:若n 是k 位的二进制数,即122k k n -≤<,(***),则()n g n +是每位均为1的k 位二进制数,即1()12221k k n g n -+=+++=- ,故()()221k f n n g n n =-=-+;而由(***)式,可得:21log k n k -≤<,所以21[log ]k n -=,(这就是要求的通项公式)从这个问题可见二进制的作用不可小视之.下面再举一例,注意分析过程. 题目:对怎样的正整数n ,方程[][2][4][8]x x x x n +++=(☆)中的x 有解? 解答:设[]x x r =+,把r 用二进制数表示:312123223(0. )222a a a r a a a ==+++ ,{0, 1}i a ∈, 则有1[2]2[]x x a =+;12212[4]4[]()4[]2x x a a x a a =+=++;1232123[8]8[]()8[]42x x a a a x a a a =+=+++; 所以123[][2][4][8]15[]73x x x x x a a a +++=+++;令12373t a a a =++,因为1a 、2a 、3a {0, 1}∈,所以t 只能取到0、1、3、4、7、8、10、11这8个值,从而当且仅当n 被15除余数为0、1、3、4、7、8、10或11时,方程(☆)才有解.比如,13579n =时有解,因为135********=⨯+,从而905.375905.5x ≤<,所以4t =,即231a a ==,[]905x =,于是有44211905(0.011)9054816ax a =+=++++ ,有无穷多个解.但是,98765t=,不适合.n=时无解,这是因为987651565845=⨯+,即5。
Josephu约瑟夫问题java实现(环形链表)
Josephu约瑟夫问题java实现(环形链表)5.4.1约瑟夫问题Josephu(约瑟夫、约瑟夫环) 问题为:设编号为 1,2,… n 的 n 个⼈围坐⼀圈,约定编号为 k(1<=k<=n)的⼈从 1 开始报数,数 到 m 的那个⼈出列,它的下⼀位⼜从 1 开始报数,数到 m 的那个⼈⼜出列,依次类推,直到所有⼈出列为⽌,由 此产⽣⼀个出队编号的序列。
5.4.2解决思路⽤⼀个不带头结点的循环链表来处理 Josephu 问题:先构成⼀个有 n 个结点的单循环链表,然后由 k 结点起从 1 开 始计数,计到 m 时,对应结点从链表中删除,然后再从被删除结点的下⼀个结点⼜从 1 开始计数,直到最后⼀个 尚硅⾕ Java 数据结构和算法 更多 Java –⼤数据 –前端 –python ⼈⼯智能 -区块链资料下载,可访问百度:尚硅⾕官⽹ 第 55页 结点从链表中删除算法结束。
代码实现//约瑟夫问题-环形链表public class Josepfu {public static void main(String[] args) {CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();circleSingleLinkedList.addBoy(5);// 加⼊ 5 个⼩孩节点circleSingleLinkedList.showBoy();circleSingleLinkedList.countBoy(1, 2, 5);}}//环形链表class CircleSingleLinkedList{//指向链表的第⼀个节点private Boy first = null;//添加num个⼩孩节点public void addBoy(int num){if (num<1)throw new RuntimeException("输⼊值错误");Boy curBoy = null;for(int i=1;i<=num;i++){Boy boy = new Boy(i);if (i==1){first = boy;first.setNext(first);//形成环curBoy = first;}else{boy.setNext(first);curBoy.setNext(boy);curBoy = boy;}}}// 根据⽤户的输⼊,计算出⼩孩出圈的顺序/**** @param startNo* 表⽰从第⼏个⼩孩开始数数* @param countNum* 表⽰数⼏下* @param nums* 表⽰最初有多少⼩孩在圈中*/public void countBoy(int startNo, int countNum, int nums) {if (nums<1||countNum<1||first==null||startNo<1||startNo>nums)throw new RuntimeException("参数有误,从新输⼊!!");//创建辅助指针,指向环形链表的最后⼀个节点Boy helper = first;while (helper.getNext()!=first){helper = helper.getNext();}//移动helper和first,使从第startNo个⼩孩开始数for (int i=0;i<(startNo-1);i++){helper = helper.getNext();first = first.getNext();}//开始数数,出圈while (helper!=first){//报数for (int i=0;i<(countNum-1);i++){helper = helper.getNext();first = first.getNext();}System.out.println("⼩孩"+ first.getNo() +"出队列:" );first = first.getNext();helper.setNext(first);}System.out.println("最后的⼩孩:"+ first.getNo());}//遍历环形链表public void showBoy(){if (first==null)throw new RuntimeException("链表为空");System.out.println("⼩孩的编号: "+first.getNo());//first⽆法移动,创建中介节点遍历链表Boy curBoy = first.getNext();//当中介节点再⼀次回到first时,表⽰链表遍历完成while (curBoy!=first){System.out.println("⼩孩的编号: "+curBoy.getNo()); curBoy = curBoy.getNext();}}}//创建boy类表⽰⼀个节点class Boy{private int no;private Boy next;public Boy(int no) {this.no = no;}public int getNo() {return no;}public void setNo(int no) {this.no = no;}public Boy getNext() {return next;}public void setNext(Boy next) {this.next = next;}}。
Josephu(约瑟夫)问题解析
Josephu(约瑟夫)问题解析Josephu问题为:设置编号为1,2,3,......n的n个⼈围坐⼀圈,约定编号为k(1<=k<=n)的⼈从1看是报数,数到m的那个⼈出列,它的下⼀位⼜从1开始报数,数到m的那个⼈出列,以此类推,直到所有⼈出列为⽌,由此产⽣⼀个出队编号的序列。
提⽰:⽤有个不带头的循环链表来处理Josephu问题:先构成⼀个有n个结点的单循环链表,然后由k结点起从1开始计数,计到m时,对应结点从链表中删除,然后再从被删除结点的下⼀个结点⼜从1开始计数,直到最后⼀个结点从链表中删除算法结束。
代码:public class Demo{public static void main(String[] args){CycLink cyclink=new CycLink();cyclink.setLen(5);cycLink.createLink();cyclink.show();}}//⼩孩class Child{//编号int no;//结点Child nextChild=null;public Child(int no){//给编号this.no=no;}}//环形链表class CycLink{//先定义⼀个指向链表第⼀个⼩孩的引⽤//指定第⼀个⼩孩的引⽤不能动,不然以后找不到他了Child firstChild=null;//定义⼀个游标Child temp=null;//表⽰共有⼏个⼩孩int len=0;//设置链表⼤⼩public void setLen(int len){this.len=len;}//初始化环形链表public void createLink(){for(int i=1;i<=len;i++){if(i==1){//创建第⼀个⼩孩Child ch=new Child(i);this.firstChild=ch;this.temp=ch;}else{//创建最后⼀个⼩孩if(i==len){Child ch=new Child(i);temp.nextChild=ch;temp=ch;temp.nextChild=this.firstChild;}else{//继续创建⼩孩Child ch=new Child(i);//连接,搭桥temp.nextChild=ch;//temp向前⾛⼀步,指向刚刚进来的孩⼦temp=ch;}}}}//打印该环形链表public void show(){Child temp=this.firstChild;do{System.out.println(temp.no);temp=temp.nextChild;}while(temp!=this.fistChild);}}优化:代码:public class Demo{public static void main(String[] args){CycLink cyclink=new CycLink();cyclink.setLen(50);cycLink.createLink();cycLink.setK(2);cycLink.setM(3);cyclink.show();cyclink.play();}}//⼩孩class Child{//编号int no;//结点Child nextChild=null;public Child(int no){//给编号this.no=no;}}//环形链表class CycLink{//先定义⼀个指向链表第⼀个⼩孩的引⽤//指定第⼀个⼩孩的引⽤不能动,不然以后找不到他了 Child firstChild=null;//定义⼀个游标Child temp=null;//表⽰共有⼏个⼩孩int len=0;int k=0;int m=0;//设置mpublic void setM(int m){this.m=m;}//设置链表⼤⼩public void setLen(int len){this.len=len;}//设置从第⼏个⼈开始数数public void setK(int k){this.k=k;}//开始playpublic void play(){Child temp=this.fistChild;//1.先找到开始数数的⼈//int i=1;i<k;因为⾃⼰也要数⼀下,所以i不能为k for(int i=1;i<k;i++){temp=temp.nexChild;}while(this.len!=1){//2.数m下for(int j=1;j<m;j++){temp=temp.nextChild;}//找到要出圈的前⼀个⼩孩,有待优化Child temp2=temp;while(temp2.nextChild!=temp){temp2=temp2.nextChild;}//3.将数到m的⼩孩,退出圈temp2.nextChild=temp.nextChild;//让temp指向数数的⼩孩temp=temp.nextChild;this.len--;}//最后⼀个⼩孩(验证)System.out.println(temp.no);}//初始化环形链表public void createLink(){for(int i=1;i<=len;i++){if(i==1){//创建第⼀个⼩孩Child ch=new Child(i);this.firstChild=ch;this.temp=ch;}else{//创建最后⼀个⼩孩if(i==len){Child ch=new Child(i);temp.nextChild=ch;temp=ch;temp.nextChild=this.firstChild;}else{//继续创建⼩孩Child ch=new Child(i);//连接,搭桥temp.nextChild=ch;//temp向前⾛⼀步,指向刚刚进来的孩⼦ temp=ch;}}}}//打印该环形链表public void show(){Child temp=this.firstChild;do{System.out.println(temp.no);temp=temp.nextChild;}while(temp!=this.fistChild);}}。
数据结构实验一约瑟夫问题
HUNAN UNIVERSITY课程实习报告题目:约瑟夫问题学生姓名刘海龙学生学号************专业班级软件1 3 0 1 指导老师李晓鸿完成日期 2 0 1 4 年11 月18 日一、需求分析1.输入的形式和输入值的范围本程序中,输入的人数n和报数值m均为整数,n、m均大于0,输入的形式为:n,m (n、m输入时用逗号隔开)2.程序功能提供用户从键盘输入约瑟夫环的关键数据,人数n和报数值m,并显示出列顺序。
3.输出的形式在DOS界面上输出这n个数的输出序列。
4.测试数据①输入(n,m均为正整数,且n>m)10,3输出3 6 9 2 7 1 8 5 10 4②输入(n,m均为正整数,且n<m)4,6输出2 1 4 3③输入(n,m均为正整数,且n=m)7,7输出7 1 3 6 2 4 5④输入 (n,m中有浮点数)8,5.56输出输入有误,请重新输入!⑤输入(n,m中有负数)-3,-8输出输入有误,请重新输入!⑥输入(n,m未按格式输入)aA2,3asf输出输入有误,请重新输入!二、概要设计抽象数据类型n(n为正整数)个人的编号为1~n,1相当于唯一的“第一元素”,n相当于唯一的“最后元素”,除最后元素n外,剩下的n-1个编号均有唯一的后继,除第一元素1外,剩下的n-1个编号均有唯一的前驱,符合线性结构,故应以线性表实现该结构。
ADT alist{数据对象:D={a i| a i∈int,i=1,2,…,n,n≥0}.数据关系:Rl={<a i-1,a i> | a i-1,a i∈D,i=2,…,n}基本操作:InitList(&L,size)//构造一个空线性表L。
Append(&L,e) //新元素e入表Remove(&L,i) //删除表中第i个元素,即将i之后的元素往前移一位。
DesList(&L)//销毁线性表,释放内存空间}无论选择哪种数据结构都应有一个结构初始化操作及相应的结构销毁操作,本程序的结构初始化操作为:InitList(&L,size),结构销毁操作为DesList(&L)。
数据结构实验二 求解约瑟夫问题
数据结构实验二求解约瑟夫问题问题描述:使用代表头节点的循环单链表解决此问题。
设有n个人围坐在一张圆桌周围,现从某个人开始从1报数,数到m的人离开。
接着从出列的下一个人开始重新从1开始报数,数到m的人又出列,如此下去直到所有的人都出列为止。
求出他们的出列序列。
问题分析:例如,当n=8,m=4时,若从第一个人开始报数(设从1开始编号),则得到的序列是:4,8,5,2,1,3,7,6。
算法:void Josephus ( int n, int m,int s ){ //生成表头节点,空单循环链表LNode * HL = new LNode ;HL -> next = HL ;int i ;//生成含有n 个节点的、节点值依次为1,2……,n的带表头节点的循环单链表For ( i = n ; i>=1; i-- ){ LNode * newptr = new LNode;Newptr -> data = i ;newptr -> next = HL -> next ;HL -> next = newptr ;}//从表头开始顺序查找出第s个节点,对应第一个开始报数的人LNode * ap = HL, *cp = HL ->next ;for ( i= 1; i<s; i++ ) {ap = cp;cp = cp->next;if ( cp = = HL ) { ap = HL; cp = HL->next ; }}//依次使n-1个人出列for ( i=1; i<n; i++ ) {//顺序查找出待出列的人,即为循环结束后cp所指向的节点for ( int j=1; j<m ;j++) {ap = cp ;cp = cp->next ;if ( cp ==HL) { ap = HL; cp = HL->next ; }}//输出cp节点的值,即出列的人cout << cp->data <<”“ ;//从单链表中删除cp节点ap -> next = cp -> next ;delete cp;//使cp指向被删除节点的后续节点cp = ap -> next ;//若cp指向了表头节点,则后移ap和cp指针if ( cp = = HL ) { ap = HL ; cp = HL-> next ; }}//使最后一人出列count << HL->next -> data << end1;//删除表头节点和表头附加节点delete HL->next ;delete HL ;}补充操作系统练习:1、有一个虚拟存储系统, 每个进程在内存占有3页数据区、1页程序区. 刚开始时数据区为空. 有以下访页序列:1、5、4、1、2、3、2、1、5、4、2、4、6、5、1试给出下列情形下的缺页次数:(1)系统采用先进先出(FIFO)淘汰算法.(2)系统采用最近最少使用(LRU)淘汰算法.(3)若采用优化(OPT)淘汰算法呢?2、设系统中有三类资源A、B和C,又设系统中有5个进程P1,P2,P3,P4和P5.在T0时刻系统状态如下:最大需求量已分配资源量剩余资源量A B C A B C A B CP1 8 6 4 1 2 1 2 1 1P2 4 3 3 3 1 1P3 10 1 3 4 1 3P4 3 3 3 3 2 2P5 5 4 6 1 1 3(1) 系统是否处于安全状态?如是,则给出进程安全序列.(2) 如果进程P5申请1个资源类A、1个资源类B和1个资源类C,能否实施分配?为什么?3、在一个两道的批处理操作系统中,有6个作业进入系统,它们的进入时刻、估计运行时间和优先级如下表所示.作业号进入时刻估计运行时间优先级JOB1 8:00 90分钟 5JOB2 8:10 30分钟 6JOB3 8:30 20分钟 3JOB4 8:50 15分钟8JOB5 9:20 10分钟 2JOB6 9:40 5分钟 4系统采用短作业优先作业调度算法,作业一旦被调度运行就不再退出.但当有新的作业投入运行时,可以按照优先级进行进程调度.(1)试给出各个作业的运行时间序列.(例如:JOB1:8:00-8:30,9:10-9:20,…)(2)试计算出作业的平均周转时间.。
数据结构:Josephus环问题
Josephus环问题实验目的:1.通过实际操作,熟悉循环链表的存储结构;2.学会如何利用循环链表解决实际问题,如Josephus环等;程序流程:1.创建循环链表,每个节点存储自身的序号;2.按照输入的间距,从循环链表中删除指定间距的节点并输出序号,直到整个链表只剩下一个元素,输出序号以完成程序。
算法及注释:1)定义元素存储节点typedef struct LNode{int data;struct LNode *next;}LNode,*LinkList;2)创建主程序界面,并从命令行输入参数int main(int argc, char *argv[]){char *t;int i,n,sum;LinkList p,r,list;printf("%d\n", argc);printf("%s\n", argv[0]);printf("总数:%s\n", argv[1]);printf("报数:%s\n", argv[2]);t=argv[1];while(*t!='\0'){if(*t<'0'||*t>'9'){printf("ERROR!\n");exit(0);}t++;}t=argv[2];while(*t!='\0'){if(*t<'0'||*t>'9'){printf("ERROR!\n");exit(0);}t++;}3)从命令行读取参数list=NULL;n=atoi(argv[2]);sum=atoi(argv[1]);4)删除间距指定的元素直到链表仅剩余一个元素是,输出结果for(i=0;i<sum;i++){p=(LinkList)malloc(sizeof(LNode));p->data=i+1;if(list==NULL) list=p;else r->next=p;r=p;}p->next=list;p=list;while(p->next!=p){for(i=0;i<n-1;i++){r=p;p=p->next;}r->next=p->next;printf("删除:%4d\n",p->data);free(p);p=r->next;}printf("最后一个人:%4d\n",p->data);free(p);}程序运行截图:。
约瑟夫问题数据结构实验报告
约瑟夫问题数据结构实验报告[正文]1.实验目的本实验的目的是分析约瑟夫问题,并设计合适的数据结构解决该问题。
2.实验背景约瑟夫问题,又称为约瑟夫环,是一个经典的数学问题。
问题描述如下:有n个人围成一圈,从第一个人开始报数,数到第m个人时将其杀死,然后从下一个人开始重新报数,数到第m个人又将其杀死,如此循环进行,直到所有人都被杀死为止。
求出最后一个被杀的人在初始序列中的编号。
3.实验设计为了解决约瑟夫问题,我们需要设计合适的数据结构来表示这个过程。
以下为实验所采用的数据结构:3.1 线性表由于约瑟夫问题是围成一圈的,因此我们选择使用循环链表来表示人围成的圈。
每个节点代表一个人,包含一个成员变量用于存储人的编号。
3.2 算法采用如下算法来解决约瑟夫问题:1.创建一个循环链表,将n个人的编号分别存入节点中。
2.初始化一个指针p指向链表的第一个节点。
3.从第一个人开始报数,每报到第m个人,将该节点从链表中删除。
4.如果链表中只剩下一个节点,此时的节点即为最后一个被杀的人,输出其编号。
4.实验步骤4.1 数据结构设计根据实验设计中的描述,我们编写了一个含有循环链表和节点的数据结构。
```cppstruct ListNode {int number;ListNode next;};```4.2 实现约瑟夫问题算法根据实验设计中的算法描述,我们编写了解决约瑟夫问题的函数。
```cppint josephusProblem(int n, int m) {// 创建循环链表// 初始化指针p// 开始报数并删除节点// 返回最后被杀的人的编号}```4.3 测试与分析我们通过输入不同的n和m值,测试了约瑟夫问题的解决函数,并对实验结果进行了分析。
5.实验结果经过测试,我们得到了约瑟夫问题的解。
6.实验总结通过本实验,我们深入了解了约瑟夫问题,并成功设计了合适的数据结构和算法解决了该问题。
附件本文档无附件。
法律名词及注释1.约瑟夫问题:亦称为约瑟夫环问题,是一个数学难题,起源于古代历史记载,已有几个世纪的历史。
joseph问题总结与体会
约瑟夫问题(Josephus Problem)是一个经典的数学和计算机科学问题,它描述了一个有n个人围成一圈,从第一个人开始报数,报到m的人出圈,然后从下一个人开始继续报数,直到所有人都出圈。
这个问题可以用递归或循环的方法解决。
以下是使用Python实现的约瑟夫问题的递归解法:
```python
def josephus(n, m):
if n == 1:
return 0
else:
return (josephus(n - 1, m) + m) % n
n = int(input("请输入总人数:"))
m = int(input("请输入报数间隔:"))
result = josephus(n, m)
print("最后出圈的人是第{}个人。
".format(result + 1))
```
通过这个问题,我们可以体会到以下几点:
1. 递归是一种强大的编程技巧,可以让代码更简洁、易读。
但需要注意的是,递归可能会导致栈溢出,因此在实际应用中要注意控制递归的深度。
2. 约瑟夫问题可以看作是一个循环结构的问题,但在递归解法中,我们将其转化为了递归调用。
这说明在解决问题时,可以尝试多种方法,找到最适合自己的解决方案。
3. 约瑟夫问题还可以用其他数据结构(如队列)来解决,这进一步说明了编程问题的解决方法是多样的,需要根据具体问题来选择合适的方法。
数据结构 约瑟夫环 课程设计
摘要:约瑟夫问题是由古罗马著名的史学家Josephus提出的问题演变而来,所以通常称为Josephus问题。
改进约瑟夫问题的描述是:编号为1,2,…,n的n 个人按顺时针方向围坐一圈,每人有一个密码Ki(整数),留作其出圈后应报到Ki后出圈。
报数方法采用顺时针报数和逆时针报数交替进行,初始密码可任意确定。
求最后剩下的人的编号。
这个就是约瑟夫环问题的实际场景,后来老师要求我们对要求中的每人所持有的密码以及第一次的报数上限值要用随机数产生。
因此约瑟夫环问题如果采用双向循环链表则能很好的解决。
循环链表的数据结构,就是将一个链表的尾元素指针指向队首元素。
p->link=head解决问题的核心步骤:先建立一个具有n个链结点,无头结点的循环链表,然后确定第一个报数人的位置,并不断地从链表中删除链结点,直到链表为空。
关键词:约瑟夫环;双向循环链表;数据结构;删除结点目录1需求分析 (3)1.1功能分析 (3)1.2设计平台 (3)2概要设计 (3)2.1类LinkList (3)2.2类Joseph (4)2.3类异常处理 (4)3详细设计和实现 (4)3.1创建结点Node (4)3.2创建双向循环链表 (5)3.3从链表中删除结点 (6)4调试与操作说明 (10)4.1调试情况 (10)4.2操作说明 (10)总结............................................ 错误!未定义书签。
致谢. (13)参考文献 (13)1需求分析1.1功能分析本次选做的课程设计是改进约瑟夫(Joseph)环问题。
我选择了和薛晶两个人来完成本次课程设计的作业。
约瑟夫环问题是一个古老的数学问题,本次课题要求用程序语言的方式解决数学问题。
此问题仅使用单循环链表就可以解决此问题。
而改进的约瑟夫问题通过运用双向循环链表,同样也能方便地解决。
在建立双向循环链表时,因为约瑟夫环的大小由输入决定。