Java数据结构与算法--Josephus(约瑟夫、约瑟夫环) 问题

1. 单向环形链表应用场景

Josephu(约瑟夫、约瑟夫环) 问题

  • Josephu 问题为:设编号为 1,2,… n 的 n 个人围坐一圈,约定编号为 k(1<=k<=n)的人从 1 开始报数,数到 m 的那个人出列,它的下一位又从 1 开始报数,数到 m 的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
  • 提示:用一个不带头结点的循环链表来处理 Josephu 问题:先构成一个有 n 个结点的单循环链表,然后由 k 结点起从 1 开始计数,计到 m 时,对应结点从链表中删除,然后再从被删除结点的下一个结点又从 1 开始计数,直到最后一个结点从链表中删除算法结束。
    游戏

2. 单向环形链表介绍

环形链表

3. Josephu 问题

1) 约瑟夫问题的示意图

约瑟夫问题的示意图
2) 约瑟夫问题-创建环形链表的思路图解

2) 约瑟夫问题-创建环形链表的思路图解
3) 约瑟夫问题-小孩出圈的思路分析图

3) 约瑟夫问题-小孩出圈的思路分析图
4) Josephu 问题的代码实现

/**
 * @author zk
 * @version 1.0.0
 * @ClassName Josepfu.java
 * @Description TODO
 * @createTime 2021年09月22日 09:09:00
 */
public class Josepfu {
    public static void main(String[] args) {
        CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList(20);
        // circleSingleLinkedList.showBoy();
        circleSingleLinkedList.countBoy(1,2);
    }
}
class CircleSingleLinkedList{
    private Integer linkedListLength;
    private Boy first = null;

    public Integer getLinkedListLength() {
        return this.linkedListLength;
    }

    public void setLinkedListLength(Integer linkedListLength) {
        this.linkedListLength = linkedListLength;
    }

    public CircleSingleLinkedList(Integer linkedListLength) {
        this.linkedListLength = linkedListLength;
        this.addBoy(linkedListLength);
    }

    private void addBoy(int nums) {
        if (nums<1){
            System.out.println("人数不能小于1");
            return;
        }

        Boy curBoy = null;
        for (int i = 1; i <= nums; i++) {
            Boy boy = new Boy(i);
            if (i==1){
                this.first = boy;
                first.setNext(first);
                curBoy = first;
            }else {
                curBoy.setNext(boy);
                boy.setNext(first);
                curBoy = boy;
            }
        }
    }

    public void showBoy(){
        if (this.first==null){
            System.out.println("链表为null");
            return;
        }

        Boy curBoy = this.first;
        while (true){
            System.out.println("小孩编号:"+curBoy.getNo());
            if (curBoy.getNext()==this.first){
                break;
            }
            curBoy = curBoy.getNext();
        }
    }
    /**
     * @Author zk
     * @Description //TODO
     * @Date 2021/9/22 9:52
     * @param startNo 表示从第几个小孩开始数数
     * @param countNum 表示数几下
     * @return void
     **/
    public void countBoy(int startNo,int countNum){
        if (this.first ==null || startNo < 1 || startNo>this.linkedListLength){
            System.out.println("输入的数据有误");
            return;
        }
        // 创建辅助对象
        Boy helper = this.first;

        // 让helper处于first后一个对象
        while (true){
            if (helper.getNext()==this.first){
                break;
            }
            helper = helper.getNext();
        }

        // 让first移动到startNo处,移动startNo-1次
        for (int i = 0; i < startNo - 1; i++) {
            this.first = this.first.getNext();
            helper = helper.getNext();
        }

        // 开始数数出圈
        while (true){
            if (helper == this.first){
                // 表示圈内只剩一个小孩
                break;
            }
            // helper 和first 同时移动countNum-1次
            for (int i = 0; i < countNum - 1; i++) {
                this.first = first.getNext();
                helper = helper.getNext();
            }
            System.out.println("要出圈的小孩为:"+ first.getNo());
            this.first = this.first.getNext();
            helper.setNext(this.first);
        }
        // 圈内只剩一个小孩
        System.out.println("圈内最后一个小孩为:"+this.first.getNo());

    }
}
class Boy{
    private Integer no;
    private Boy next;

    public Boy(Integer no) {
        this.no = no;
    }

    public Integer getNo() {
        return no;
    }

    public void setNo(Integer no) {
        this.no = no;
    }

    public Boy getNext() {
        return next;
    }

    public void setNext(Boy next) {
        this.next = next;
    }
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小凯子丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值