【C#】约瑟夫原理举例2个代码实现

欢迎来到《小5讲堂》
大家好,我是全栈小5。
这是《C#》系列文章,每篇文章将以博主理解的角度展开讲解,
特别是针对知识点的概念进行叙说,大部分文章将会对这些概念进行实际例子验证,以此达到加深对知识点的理解和掌握。
温馨提示:博主能力有限,理解水平有限,若有不对之处望指正!

【C#】约瑟夫原理举例2个代码实现_第1张图片

目录

  • 前言
  • 原理实现
    • 递归方法
    • 循环队列
    • 值不同
  • 相关文章

前言

上篇文章有讲到扑克牌魔术,经过了解,使用了约瑟夫原理。
处于好奇了解了下基本概念以及通过简单代码实现下。

原理实现

在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}"); 
    }  
}

【C#】约瑟夫原理举例2个代码实现_第2张图片

循环队列

使用队列(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}");  
    }  
}

【C#】约瑟夫原理举例2个代码实现_第3张图片

值不同

上面两个方法输出的值不同,是因为它们计算最后存活者位置的方式不同。

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#】约瑟夫原理举例2个代码实现_第4张图片

相关文章

【C#】使用代码实现刘谦龙年春晚扑克牌魔术(守岁共此时),代码实现篇
【C#】使用代码实现刘谦龙年春晚扑克牌魔术(守岁共此时),流程描述篇
【C#】约瑟夫原理举例2个代码实现
【C#】List泛型数据集如何循环移动,最后一位移动到第一位,以此类推

温故而知新,不同阶段重温知识点,会有不一样的认识和理解,博主将巩固一遍知识点,并以实践方式和大家分享,若能有所帮助和收获,这将是博主最大的创作动力和荣幸。也期待认识更多优秀新老博主。

你可能感兴趣的:(C#,c#,开发语言)