欢迎来到《小5讲堂》
大家好,我是全栈小5。
这是《C#》系列文章,每篇文章将以博主理解的角度展开讲解,
特别是针对知识点的概念进行叙说,大部分文章将会对这些概念进行实际例子验证,以此达到加深对知识点的理解和掌握。
温馨提示:博主能力有限,理解水平有限,若有不对之处望指正!
前言
上篇文章有讲到扑克牌魔术,经过了解,使用了约瑟夫原理。
处于好奇了解了下基本概念以及通过简单代码实现下。
原理实现
在C#中实现约瑟夫原理(Josephus Problem)可以有多种方式。
下面我将给出两个例子,一个使用递归方法,另一个使用循环队列(Queue)数据结构。
递归方法
递归方法是一种直观的实现方式,但由于递归过程中会生成大量的函数调用栈,因此对于大量的人数可能会遇到栈溢出的问题。
using System;
class JosephusProblem
{
static int LastManStanding(int total, int step)
{
if (total == 1)
return 0;
return (LastManStanding(total - 1, step) + step) % total;
}
static void Main(string[] args)
{
int totalPeople = 10; // 总人数
int step = 2; // 报数到2的人出列
int lastPersonIndex = LastManStanding(totalPeople, step);
Console.WriteLine($"最后一个人站在位置: {lastPersonIndex + 1}");
}
}
循环队列
使用队列(Queue)来模拟围圈的过程是一个更高效的实现方式,因为它避免了递归带来的栈空间问题。
using System;
using System.Collections.Generic;
class JosephusProblem
{
static int LastManStanding(int total, int step)
{
Queue<int> queue = new Queue<int>();
// 初始化队列,编号从0开始
for (int i = 0; i < total; i++)
{
queue.Enqueue(i);
}
int position = 0; // 起始位置
while (queue.Count > 1)
{
// 跳过step-1个人
for (int i = 0; i < step - 1; i++)
{
position = (position + 1) % queue.Count;
}
// 移除当前位置的人
queue.Dequeue();
// 更新位置
position = (position + 1) % queue.Count;
}
return queue.Dequeue(); // 返回最后一个人的编号
}
static void Main(string[] args)
{
int totalPeople = 10; // 总人数
int step = 2; // 报数到2的人出列
int lastPersonIndex = LastManStanding(totalPeople, step);
Console.WriteLine($"Last person standing is at position: {lastPersonIndex + 1}");
}
}
值不同
上面两个方法输出的值不同,是因为它们计算最后存活者位置的方式不同。
1.递归方法实现:
递归方法LastManStanding通过递归调用自身来计算最后存活者的位置。它假设从第一个人开始报数,每次跳过step-1个人,然后移除那个人。递归的基准情况是当总人数为1时,返回0作为最后存活者的位置。这个方法有一个问题,即它实际上计算的是最后存活者在原始编号中的位置,而不是从1开始的编号位置。因此,如果你直接打印返回的索引值,它会是从0开始的。
2.循环队列实现:
循环队列实现的方法也计算最后存活者的位置,但是它从1开始编号,并且维护了一个循环队列来模拟围圈的人。每次移除一个人时,它更新位置以确保它是从当前存活者之后的下一个人开始计算的。因此,这个方法返回的是从1开始的最后存活者的位置。
要使两个方法输出相同的结果(即从1开始的最后存活者的位置),需要在递归方法的结果上加1,或者在打印结果时加1。
- 下面是修改后的递归方法示例,使其输出与循环队列实现相同的结果:
static int LastManStanding(int total, int step)
{
if (total == 1)
return 0; // 基准情况,返回0,因为编号从0开始
// 计算从1开始的最后存活者的位置
return (LastManStanding(total - 1, step) + step) % total + 1;
}
相关文章
【C#】使用代码实现刘谦龙年春晚扑克牌魔术(守岁共此时),代码实现篇
【C#】使用代码实现刘谦龙年春晚扑克牌魔术(守岁共此时),流程描述篇
【C#】约瑟夫原理举例2个代码实现
【C#】List泛型数据集如何循环移动,最后一位移动到第一位,以此类推
温故而知新,不同阶段重温知识点,会有不一样的认识和理解,博主将巩固一遍知识点,并以实践方式和大家分享,若能有所帮助和收获,这将是博主最大的创作动力和荣幸。也期待认识更多优秀新老博主。