算法-使用链表解决约瑟夫问题

88 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第14天,点击查看活动详情

问题描述: 约瑟夫问题:有 N 个人围成一圈,每个人都有一个编号,编号由入圈的顺序决定,第一个入圈的人编号为 1,最后一个为 N,从第 k (1<=k<=N)个人开始报数,数到 m (1<=m<=N)的人将出圈,然后下一个人继续从 1 开始报数,直至所有人全部出圈,求依次出圈的编号。

思路分析

根据问题描述 可以讲每个人看成一个节点,上一个人指向下一个人,最后一个指向第一个,如此构建一个环形链表,假如有五个人,构建的环形链表如下:

image.png

出队列 当 重k开始的 数m下之后 出队列 只需要将那个节点的上一个节点的指针指向这个节点的下一个节点

代码实现

  1. 构建节点类
class JosephusNode{
    int number;
    JosephusNode next;

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    public JosephusNode getNext() {
        return next;
    }

    public void setNext(JosephusNode next) {
        this.next = next;
    }

    @Override
    public String toString() {
        return "JosephusNode{" +
                "number=" + number +
                ", next=" + next +
                '}';
    }

2.创建环形链表方法

public static JosephusNode createNodes(int size){
     //头节点
    JosephusNode josephusNode = new JosephusNode();
    //虚拟指针指向最后一个节点
    JosephusNode tail = josephusNode;
    //虚拟指针指向最后一个节点
    JosephusNode head = josephusNode;
    for (int i = 0; i <size ; i++) {
        if(i+1 ==size){
            tail.setNext(head);
            continue;
        }
        JosephusNode josephusNodeNext = new JosephusNode();
        josephusNodeNext.setNumber(i+1);
        //链接在最后一个节点后面
        tail.setNext(josephusNodeNext);
        tail = josephusNodeNext;
    }
    return  josephusNode;
 }

3.出队列

 public static  void outOfTheTeam(JosephusNode nodes,int k,int m){
        JosephusNode curNode = nodes;
        JosephusNode curNodeLast = nodes;
        //指向第k个节点
        for (int i = 0; i < k-1; i++) {
            curNode = curNode.getNext();
        }
        //指向第k个节点的前一个节点
        for (;;) {
            if(curNodeLast.getNext() == curNode){
                break;
            }
            curNodeLast = curNodeLast.getNext();
        }
        int count =1;
        while (true){
            if(curNode.getNumber()==curNode.getNext().getNumber()){
                System.out.println(curNode.getNext().getNumber());
                break;
            }
            if(count == m){
                count =0;
                //出圈
                System.out.println(curNode.getNumber());
                //将当前节点的下一个节点 赋值给curNodeLast的下一个节点 完成出圈
                JosephusNode curNodeDeleteNext = curNode.getNext();
                curNodeLast.setNext(curNodeDeleteNext);
                curNode = curNodeLast.getNext();
//                curNode.getNext().setNext(null);
            }else{
                //不出圈都往后移
                curNode= curNode.getNext();
                curNodeLast= curNodeLast.getNext();
            }
            count ++;

        }
    }

测试结果如下(我的节点是以0开头的):

image.png

3 7 4 1 0 2 6 5