zoukankan      html  css  js  c++  java
  • C#数据结构与算法系列(七):约瑟夫问题(Josephu)

    1.介绍

    Josephu问题为:设编号为1、2、...n的n个人围坐在一圈,约定编号为k(1<=k<=n) 的人从1开始报数,

    数到m的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,以此类推,直到所有人都出列为止,由此产生出一个出列编号的序列。

    2.提示

    用一个不带头节点的循环链表来处理Josephu问题:先构成一个有n节点的单向循环链表,

    然后由k节点起从1开始计数,计到m时,对应节点从链表中删除,然后再重被删除节点的下一个节点又从1开始计数,直到最后一个节点从链表中删除算法结束

    3.示意图

     4.环形链表示意图

     5.思路分析图

     6.代码实现

        public class Boy
        {
            public Boy(int id)
            {
                this.Id = id;
            }
            public int Id { get; set; }
    
            public Boy Next { get; set; }
        }
        public class CircleSingleLinkList
        {
            private Boy _first = null;
    
            public void Add(int nums)
            {
                if (nums < 1) Console.WriteLine("传入的值必须大于1");
                else
                {
                    Boy curBoy = null;
    
                    for (int i = 1; i <= nums; i++)
                    {
                        Boy boy = new Boy(i);
    
                        if (i == 1)
                        {
                            _first = boy; 
                            _first.Next = _first; //构成环形
                            curBoy = _first; //让当前boy等于第一个小孩
                        }
    
                        else
                        {
                            curBoy.Next = boy; //指向当前小孩的下一个
                            boy.Next = _first; //待添加的小孩的下一个节点指向第一个
                            curBoy = boy;//再把当前小孩指向待添加节点
                        }
                    }
                }
            }
    
            /// <summary>
            /// 根据用户的输入,计算出小孩出圈的顺序
            /// </summary>
            /// <param name="startId">表示从第几个小孩开始数数</param>
            /// <param name="countNum">表示数几下</param>
            /// <param name="nums">表示最初由几个小孩在圈中</param>
            public void CountBoy(int startId,int countNum,int nums)
            {
                if (startId < 1 || startId > nums || _first == null)
                {
                    Console.WriteLine("参数错误请重新输入");
    
                    return;
                }
    
                Boy helper = _first; //创建一个辅助节点
    
                //将辅助节点指向最后一个节点
                while (true)
                {                
                    if (helper.Next == _first) break; //当辅助节点的下一个节点等于第一个节点 说明是最后一个节点
    
                    helper = helper.Next; 
                }
    
                //将开始节点和辅助节点指向开始数数的位置和结尾  由于索引是从0开始所以是startId-1
                for (int j = 0; j < startId-1 ; j++)
                {
                    _first = _first.Next;
                    helper = helper.Next;               
                }
    
                //当小孩报数时,让first和helper同时移动 countNum-1次,然后出圈
                while (true)
                {
                    if (helper == _first) break;  //当尾结点等于头节点时 说明只有一个节点
    
                   
                    for (int i = 0; i < countNum-1; i++)
                    {
                        _first = _first.Next;
                        helper = helper.Next;
                    }
    
                    //first就代表出圈的小孩
                    Console.WriteLine($"出圈的小孩:{_first.Id}");
    
                    _first = _first.Next; //将first指向小孩节点出圈
                    helper.Next = _first;
                }
                Console.WriteLine("最后留下的小孩:"+_first.Id);
            }
        public class Josephu
        {
            public static void Test()
            {
                CircleSingleLinkList singleLinkList = new CircleSingleLinkList();
    
                singleLinkList.Add(5);
    
                singleLinkList.ShowBoy();
    
                singleLinkList.CountBoy(1, 2, 5);
            }
        }

    7.效果演示图

  • 相关阅读:
    Python 缓冲区
    Python接收执行参数
    Python编码
    Maven 多环境 打包
    JS 时间 获取 当天,昨日,本周,上周,本月,上月
    Window Mysql 5.7.18安装
    Eclipse 更改Maven项目名
    Redis 命令
    Redis 安装 和 启动
    Mongodb 安装 和 启动
  • 原文地址:https://www.cnblogs.com/vic-tory/p/13152400.html
Copyright © 2011-2022 走看看