小耗子出圈 约瑟夫环经典算法问题

环链表实现


/**
 * 约瑟夫环问题
 * <p>
 * 约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知 n 个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。从编号为 k 的人开始报数,数到 m
 * 的那个人出圈;他的下一个人又从 1 开始报数,数到 m 的那个人又出圈;依此规律重复下去,直到剩余最后一个胜利者。
 * <p>
 * 例如:有10个人围成一圈进行此游戏,每个人编号为 1-10 。若规定数到 3 的人出圈。则游戏过程如下。
 */
public class JosepfuDome {
    public static void main(String[] args) {
        CircleSingleQueue circleSingleQueue = new CircleSingleQueue();
        circleSingleQueue.addBoy(10);// 构建10人的链表环
        circleSingleQueue.show();
        circleSingleQueue.conutBoy(1,3,10);
    }
}
//创建环形的列表
class CircleSingleQueue {
    // 创建初始节点 辅助作用
    private BoyNode first = null;
    /**
     * 添加信息构成环形的列表
     *
     * @param nums 添加的节点小孩的数量 数据递增
     */
    public void addBoy(int nums) {
        // 先对数据进行校验
        if (nums <= 0) {
            System.out.println("请正确的输入");
            return;
        }
        // 创建辅助指针 小孩
        BoyNode cur = null;
        // 使用循环创建环形链表
        for (int i = 1; i <= nums; i++) {
            // 创建新的节点
            BoyNode boy = new BoyNode(i);
            if (i == 1) {
                first = boy;
                first.setNext(first);
                cur = first;
            } else {
                cur.setNext(boy);
                boy.setNext(first);
                cur = boy;
            }
        }
    }
    /**
     * 小孩出圈
     *
     * @param startNo  开始数的孩子
     * @param countNum 数到几进行出圈
     * @param boyNum   是几人的圈
     */
    public void conutBoy(int startNo, int countNum, int boyNum) {
        //进行简单的数据校验
        if (first == null || startNo < 1 || startNo > boyNum) {
            System.out.println("参数不正确 请重新输入");
            return;
        }
        //因为需要选择而开始的孩子 需要将第一个节点移动到startNo的编号节点
        for (int i = 0; i < startNo - 1; i++) {
            first = first.getNext();
        }
        //创建辅助指针进行链表的遍历出圈
        BoyNode assistCur = first;
        //遍历链表将辅助指针移动到链表的最后一个节点
        while (true) {
            if (assistCur.getNext() == first) {
                break;
            }
            //进位
            assistCur = assistCur.getNext();
        }
        //现在的辅助指针指向了链表的最后一个节点 开始报数
        while (true) {
            if (assistCur == first) {
                break;
            }
            //初试辅助指针first  assistCur 同时进行countNum-1
            for (int i = 0; i < countNum - 1; i++) {//重点就是这个移动造成first指针指向了要出圈的小孩的位置
                first = first.getNext();
                assistCur = assistCur.getNext();
            }
            //现在的小孩就是要出圈的小孩的编号
            System.out.printf("小耗子%d出圈\n", first.getNo());
            first=first.getNext();
            assistCur.setNext(first);
        }
        System.out.printf("%d获胜者\n", first.getNo());
    }
    /**
     * 展示链表
     */
    public void show() {
        // 判断是否为空
        if (first == null) {
            System.out.println("链表为空");
            return;
        }
        // 创建辅助指针 小孩
        BoyNode cur = first;
        while (true) {
            System.out.printf("小孩的编号" + cur.getNo() + "\n");
            if (cur.getNext() == first) {
                break;
            }
            cur = cur.getNext();
        }
    }
}
//创建节点
class BoyNode {
    private int no;
    private BoyNode next;
    // 构造器
    public BoyNode(int no) {
        this.no = no;
    }
    public int getNo() {
        return no;
    }
    public void setNo(int no) {
        this.no = no;
    }
    public BoyNode getNext() {
        return next;
    }
    public void setNext(BoyNode next) {
        this.next = next;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值