单链表实现约瑟夫问题

什么是约瑟夫问题

设编号为 1,2,… n 的 n 个人围坐一圈,约定编号为 k(1<=k<=n)的人从 1 开始报数,数到 m 的那个人出列,它的下一位又从 1 开始报数,数到 m 的那个人又出列,依次类推,直到所有人出列为止,由此 产生一个出队编号的序列
在这里插入图片描述

分析

1)创建一个尾辅助指针指向最后一个节点(头节点的前一个节点)
2)报数前根据输入的开始位置坐标进行移动firstNode头节点以及helperNode尾节点(移动输入次数-1次因为开始数的节点也会报数)
3)报数时根据输入的报数间隔进行移动firstNode节点以及helperNode尾节点(移动输入次数-1次因为开始数的节点也会报数)
4)这时的首节点则是出列节点,直接进行输出即可
5)当firstNode头节点等于helperNode尾节点时说明链表中只剩下最后一个元素直接进行出列即可

代码实现

/**
 * 定义一个单向列表用于解决约瑟夫问题
 * */
public class Node {
    private int id;
    private Node nextNode;

    public Node(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public Node getNextNode() {
        return nextNode;
    }

    public void setNextNode(Node nextNode) {
        this.nextNode = nextNode;
    }

    @Override
    public String toString() {
        return "Node{" +
                "id=" + id+
                '}';
    }
    }
/**
 * 循环单向链表解决约瑟夫问题
 */
public class CyclicLinkedList {
    Node first = null;
    /**
     * 增加nums个小朋友到循环队列里
     * */
    public void addBoy(int nums){
        if(nums==0){
            throw new RuntimeException("数量错误");
        }
        //辅助指针,帮助构建环形链表
        Node lastNode = null;
        for(int i = 1;i<=nums;i++){
            Node node = new Node(i);
            //如果是首个节点需要记录下来用于遍历
            if(i==1){
                first = node;
                //自己也能进行循环
                first.setNextNode(first);
                //让辅助变量指向节点
                lastNode = first;
            }else{
                //这里注意 lastNode可以直接新增因为lastNode = first这里还是指向同一个地址所以下面直接遍历first即可
                lastNode.setNextNode(node);
                //新增节点与头节点循环连接起来
                node.setNextNode(first);
                //让辅助变量指向最后节点
                lastNode = node;
            }
        }
    }
    /**
     * 遍历当前链表
     * */
    public void ergodic(){
        Node node = first;
        while(true){
            if(node.getNextNode()==first){
                break;
            }
            System.out.println(node.getId());
            node = node.getNextNode();
        }
        System.out.println(node.getId());
    }
    /**
     * 出圈操作
     * @param start 开始的位置坐标
     * @param num 每次间隔几个数字进行出圈
     * */
    public void OutNode(int start,int num){
        if(first==null){
            throw new RuntimeException("链表为空");
        }
        //第一步创建一个尾辅助指针指向最后一个节点
        Node helperNode = first;
        while(true){
            if(helperNode.getNextNode()==first){
                break;
            }
            helperNode = helperNode.getNextNode();
        }
        //根据输入的开始位置坐标进行移动firstNode节点以及helperNode尾节点
        for(int c = 0;c<start-1;c++){
            helperNode = helperNode.getNextNode();
            first = first.getNextNode();
        }
        //出列操作
        while(true){
            //链表只剩下了头节点这时候直接输出即可
            if(helperNode==first){
                break;
            }
            //根据用户输入每次出列间隔个数进行出列操作
            for(int k = 0;k<num-1;k++){
                helperNode = helperNode.getNextNode();
                first = first.getNextNode();
            }
            //当前头节点就是出列的节点
            System.out.println("出列:"+first.getId());
            //把头节点向后移动一位并把尾辅助节点的下一个节点指向头节点
            first = first.getNextNode();
            helperNode.setNextNode(first);
        }
        //输出最后一个节点
        System.out.println("最后节点"+first.getId());
    }
}

测试

public static void main(String[] args) {
        CyclicLinkedList cyclicLinkedList = new CyclicLinkedList();
        cyclicLinkedList.addBoy(5);
        cyclicLinkedList.ergodic();
        cyclicLinkedList.OutNode(1,2);
    }

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值