zoukankan      html  css  js  c++  java
  • 单向环形链表解决约瑟夫环(Josephus)问题

    一、约瑟夫环问题

    Josephu 问题为:设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。

    二、解决思路

    ​ 用一个不带头结点的循环链表来处理Josephu 问题:先构成一个有n个结点的单循环链表,然后由k结点起从1开始计数,计到m时,对应结点从链表中删除,然后再从被删除结点的下一个结点又从1开始计数,直到最后一个结点从链表中删除算法结束。

    三、实现代码

    1.需要的数据结构

    节点

    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;
        }
        @Override
        public String toString() {
            return "Boy{" +
                    "no=" + no +
                    '}';
        }
    }
    

    单向环形链表

    class CircleList{
    
        private Boy first = null;
    
        /**
         *
         * @param startNo   从第几个小孩开始数
         * @param countNo   每次数几下
         * @param nums 小孩的数量
         */
        public void outOfCircle(int startNo, int countNo,int nums){
            if (first==null || startNo<1|| startNo>nums){
                System.out.println("参数输入有误");
                return;
            }
            //创建辅助指针helper即要出圈小孩的前一个节点
            Boy helper = first;
            while (true){
                if (helper.getNext()==first){
                    break;//helper已经到达first前的节点
                }
                helper=helper.getNext();
            }
            //移动到开始报数的位置
            for (int i = 0; i <startNo-1 ; i++) {
                first = first.getNext();
                helper =helper.getNext();
            }
            //开始报数
            while(true){
                if(helper == first){//只有一个节点
                    break;
                }
                for (int i = 0; i <countNo-1 ; i++) {
                    //1、寻找待出圈的小孩、循环完成时,first就是要出圈的小孩
                    first = first.getNext();
                    helper =helper.getNext();
                }
                System.out.printf("出圈小孩编号:%d
    ",first.getNo());
                helper.setNext(first.getNext());
                first=first.getNext();
            }
            System.out.printf("最后留在圈中的小孩编号:%d
    ",first.getNo());
        }
    
    
        public void addBoy(int nums){
            if (nums<1){
                System.out.println("数量有误");
                return;
            }
            Boy curBoy =null;
            for (int i = 0; i < nums; i++) {
                Boy boy =new Boy(i+1);
                //如果是第一个小孩,指向本身
                if (i==0){
                    first=boy;
                    first.setNext(first);
                    curBoy=first;
                }else{
                    curBoy.setNext(boy);
                    boy.setNext(first);
                    curBoy=boy;
                }
            }
        }
    
        public void display(){
            if (first==null){
                System.out.println("链表为空");
                return;
            }
            Boy curBoy = first;
            while(true){
                System.out.printf("小孩的编号:%d
    ",curBoy.getNo());
                if (curBoy.getNext()==first){
                    break;
                }
                curBoy=curBoy.getNext();//后移
            }
        }
    }
    
    2.测试代码与结果

    测试类

    public class Josepfu {
    
        public static void main(String[] args) {
            CircleList c = new CircleList();
            c.addBoy(5);
            c.outOfCircle(1,2,5);
        }
    
    }
    

    运行结果

  • 相关阅读:
    《spring实战》学习笔记-第五章:构建spring web应用程序
    magento函数getChildHtml() 与getChildChildHtml() 的用法
    生成2048公私钥
    magento购物车对象
    关于文本超出宽度自动隐藏
    调用一个静态块
    js 判断是否为正数
    更改商品的库存数量
    配置文件进行编辑
    首页显示产品的数量的展示
  • 原文地址:https://www.cnblogs.com/polary/p/12868584.html
Copyright © 2011-2022 走看看