java约瑟夫环迭代器_Josephus约瑟夫环问题的不同实现方法与总结
/************************************************************************/
/* Josephus问题——数组实现 */
/************************************************************************/
#include
#include
int Josephus(int times, int number, int id){
int *a;
int i, count = 0, t = 0;
a = (int *)malloc(sizeof(int) * number);
for(i = 0; i < number; i++)
a[i] = i + 1; // 数组a用于储存每个元素的编号
i = id - 1;
while(count < number - 1){
if(a[i] != 0)
t++;
if(t == times){
t = 0;
count++;
printf("%4d", a[i]);
a[i] = 0; // 当该元素被剔除时,该数组元素置为0
}
i++;
if(i == number)
i = 0;
}
for(i=0;i
if(a[i]!=0)
{
printf("\n最后剩余的结点是:%4d\n",a[i]);
return;
}
}
int main(){
int times, number, id;
printf("请输入总人数:");
scanf("%d", &number);
printf("请输入报数周期:");
scanf("%d", ×);
printf("请输入开始报数的编号:");
scanf("%d", &id);
Josephus(times, number, id);
return 0;
}
/************************************************************************/
/* 总结:
优点为可以得出每次被剔除的元素编号
缺点为内存空间占用较大,没有数学归纳法快速 */
/************************************************************************/
/************************************************************************/
/* Josephus问题——循环链表实现 */
/************************************************************************/
#include
#include
typedef struct LNode
{
int data;
struct LNode *next;
}LNode,*Linkhead;
void Josephus(int m,int n,int k)
{
Linkhead p,r,head = NULL;
int i;
for(i = 1;i <= n;i++)
{
p = (Linkhead)malloc(sizeof(LNode));//申请一个新的链结点
p->data = i;//存放第i个结点的编号
if(head == NULL)
head = p;
else
r->next = p; // 因为Insert和Del操作都需要之前一个节点的地址,故用r来存储。其作用类似栈的top
r = p;
}
p->next = head;//至此,建立一个循环链表
p = head;
for(i = 1;i < k;i++)
{
r=p;
/*请注意,此行不是多余的,因为当k!=1,但m=1时如果没有这条语句,此时删除动作无法完成*/
p=p->next;
} //此时p指向第1个出发结点
while(p->next != p)
{
for(i = 1;i < m;i++)
{
r = p;
p = p->next;
} //p指向第m个结点,r指向第m-1个结点
r->next = p->next; //删除第m个结点
printf("%4d",p->data); //依次输出删除结点的编号
free(p); //释放被删除结点的空间
p = r->next; //p指向新的出发结点
}
printf("\n最后剩余的结点是:%4d\n",p->data);//输出最后一个结点的编号
}
int main(){
int times, number, id;
printf("请输入总人数:");
scanf("%d", &number);
printf("请输入报数周期:");
scanf("%d", ×);
printf("请输入开始报数的编号:");
scanf("%d", &id);
Josephus(times, number, id);
return 0;
}
/************************************************************************/
/* 总结:
优点为可以得出每次被剔除的元素编号
缺点为相较数组方法需要更多的计算量
总体而言与数组方法相差无几 */
/************************************************************************/
/************************************************************************/
/* Josephus问题——数学归纳法直接计算 */
/************************************************************************/
#include
int main() {
int answer = 0;
int times, number, i, id; // number为环内总元素个数,times为报数周期, id为从第几个元素开始报数
printf("请分别输入总人数和循环次数:");
scanf("%d %d", &number, ×);
printf("起始报号者的编号:");
scanf("%d", &id);
for(i = 1; i <= number; i++) {
answer = (answer + times) % i; // 核心算法,利用数学归纳法得出
}
if(answer + id == number)
printf("Survial: %d\n", number); // 防止当幸存者为最后一个编号时输出0的情况
else
printf("Survival: %d\n",(answer + id) % number);
// 这边利用number对answer进行取余操作以防止编号数值超过最大编号(溢出)
return 0;
}
对于Josephus问题有两个地方是可以进行优化的。 (总人数为N,编号为从0~N-1;经过M次报数去除一个成员,剩余成员个数为numleft, 记M%numleft为mPrime)
1、被移除的成员离上一个成员之间的距离是M%numleft-1(报数次为M%numleft).当M大于N时,该计算方式将节省大量时间
2、当mPrime大于numleft的时候可以反向遍历该表来查找要去除的成员。这样可以节省时间。同样这也就要求了该表必须是一个双向表才行。(即含有Previous方法)
该算法实现原理即为:
第一轮,必定为编号M%N-1的成员被去除,第二轮为在第一轮的基础上即从编号为M%N的成员开始正移mPrime-1个单位(或者反移numleft-mPrime-1个单位)。若将M%N即为编号0,开始重新编号,那么第二轮被删除的成员编号便是M%(numleft)-1,由此可得该轮要被删除的成员与上一轮去除成员之间的距离为M%numleft,这里可利用迭代器来实现。
这里我们便可以得到成员编号与该轮成员数目的关系是:(n表示该轮所剩余的成员数目,Index(n)表示该轮成员的编号(从0开始))
Index(n) = (Index(n - 1) + m) % n。
那么按照这个过程,我们这样一直移除元素下去,肯定能够找到最后一个被移除的元素。
这个元素则对应只有一个元素的环,很显然,它的值为0。也就是Index(1) = 0。
对于这个元素的索引,它对应两个元素的索引是多少呢?
按照前面的过程,我们倒推回去就是了。Index(2) = (Index(1) + m) % 2。
那么对应3个,4个元素的呢?我们这样一路继续下去就可以找到对应到n个元素的索引了。
所以,我们发现了一个有意思的数学归纳关系:
f(1) = 0, f(n) = (f(n - 1) + m) % n。
按照这个关系,我们可以得到最后一个被取出来的元素对应到n个元素的环里的索引值。
至此,我们可以发现,利用count计数从而删除成员的方法与此相比起来逊色不少,故之后我们将采用此方法来解决问题。
该问题的最终解决程序可参见另一篇文章: Java实现 Josephus约瑟夫环问题 http://www.linuxidc.com/Linux/2017-05/144055.htm
java约瑟夫环迭代器_Josephus约瑟夫环问题的不同实现方法与总结相关推荐
- java实现环形链表解决约瑟夫环问题
什么是环形链表? 环形链表就是单向链表的基础上让链表的首尾相连,形成一个环,这就是一个循环链表. 什么是约瑟夫环问题? 约瑟夫环如下: 约瑟夫问题是个著名的问题:N个人围成一圈,第一个人从1开始报数, ...
- Java中使用链表解决约瑟夫问题(丢手绢问题)
文章目录 文章目录 前言 一.思路分析 二.代码实现 1.Chird类建立 2.链表创建 3.功能实现 总结 其他解决方式: Java中使用list解决约瑟夫问题https://blog.csdn.n ...
- c语言链表如何做成环,在C语言中单向链表环测试并返回环起始节点的实现方法...
小编想问大家一个问题,就是如果我们需要进行测试一个单向链表是否存在环,应该使用什么方法才是最好的呢?如果大家还不知道有什么方法的话,那就接着往下面看哟!因为今天小编就要为大家介绍一下:在C语言中单向链 ...
- 数据调度系统中有向无环图的无环检测
数据调度系统中有向无环图的无环检测 名词解释 DAG,全称:Directed Acyclic Graph,中文:有向无环图 入度:有向图中某点作为图中边的终点的次数之和 出度: 对于有向图来说,顶点的 ...
- 【刷算法】判断链表是否有环以及返回入环节点
题目描述 判断一个单链表是否有环,有环则返回入环节点,否则返回null 1->2->3->4->5->6↑ ↓8<-7 复制代码 例如上面这个链表就有环,入环节点是 ...
- STM32 电机教程 15 - BLDC 速度环内嵌电流环
前言 无刷直流 (Brushless Direct Current, BLDC)电机是一种正快速普及的电机类型,它可在家用电器.汽车.航空航天.消费品.医疗.工业自动化设备和仪器等行业中使用.正如名称 ...
- 【学习笔记】无向图、有向图的三元环、四元环计数问题(根号分支+bitset)
三元环计数和四元环计数问题 无向图三元环计数问题 根号分治 bitset 无向图四元环计数问题 有向图三四元环计数问题 无向图三元环计数问题 根号分治 记 di:id_i:idi:i 在原图中的度数 ...
- Java中的迭代器设计模式–示例教程
迭代器模式是一种行为模式,用于提供遍历一组对象的标准方式. Iterator模式在Java Collection Framework中得到了广泛使用,其中Iterator接口提供了遍历集合的方法. 根 ...
- ]数据结构:单链表之判断两个链表是否相交及求交点(带环、不带环)
1.判断两个链表是否相交,若相交,求交点.(假设链表不带环) 两个指针同时指向两个链表,分别依次往后遍历链表到最后一个节点,如指针的值相同(即节点地址相同),反之没有交点. int IsCross(N ...
最新文章
- hadoop运行中报错笔记
- 【Java】Servlet 工作原理解析
- ceph单节点安装部署
- 《Android进阶之光》--View体系与自定义View
- 开源项目几点心得,Java架构必会几大技术点
- 2017.10.5 高速公路 思考记录
- C语言之预处理探究(三):头文件包含
- 在线node服务器,如何将你的node服务放到线上服务器
- 合成文字识别需要的训练竖排文字数据集
- 使用计算机辅助翻译的基本流程,计算机辅助翻译不同于机器翻译,计算机辅助翻译的原理和流程...
- java excel换行_java poi出excel换行问题
- 7. gdal进行遥感影像的16位转8位和百分比截断增强(看这篇就够了)
- 腾讯不缺少梦想,但是缺算法与数据管理
- 古今中外著名14大悖论
- 第三方支付(微信支付)支付流程分析
- HTML5 Canvas组件绘制太极图案
- Echarts实现省级到市级地图下钻
- Java中调整字距与行距的方法 其一(以DrawString为例)
- 如何实现web系统检测浏览器类型的功能
- 手机上传文件到ftp服务器,上传文件到iPhone上的FTP服务器(Upload File to FTP Server on i...
热门文章
- C++获取指向二维数组的首元素指针
- 从‘一边拉琴,一边哭’,看什么是真正的兴趣
- MFC中为菜单命令添加快捷键
- 三个数据集与deploy.prototxt
- CompletableFuture详解~thenApply
- java元素符号是什么_Java 代码中 @ 符号是什么意思?
- android点击通知后消失,通知栏点击后消失解决方法
- 外设驱动库开发笔记38:RTD热电阻测温驱动
- 记录---基于BigDecimal的特殊的四舍五入
- java post请求返回500错误信息_Retrofit API Post call 返回错误 500,适用于 Postman