JAVA算法—Josephu(约瑟夫)问题

Josephu(约瑟夫)问题

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

  • n = 6 一共有6人
  • k = 2 从编号2的人开始从1报数
  • m = 2 报数报到2的人出列
    在这里插入图片描述

解题思路

环形单链表来完成

构建环形链表和节点(节点表示人)

  1. 首先创建第一个节点first,让first指向自己形成环形。
  2. 每添加新的节点,将新节点加入环形链表中。

根据用户输入的参数,实现人出列的

  1. 先将first节点定位到编号为k的节点。
  2. 使用辅助节点temp,指向first的前一个节点。
  3. 报数时first和temp移动(m-1)次
  4. 这是first就是需要出列的节点。
  5. temp指向first的后一个节点,实现出列。
  6. 等到节点只剩一个时,返回改节点完成!

代码实现

public class Solution {

    public static void main(String[] args) {//测试
        CircleSingleLinkedList list = new CircleSingleLinkedList();
        list.addNode(5);
        int no = list.exit(1, 2).no;
        System.out.println(no);

    }
}

class CircleSingleLinkedList{//创建环形单链表
    private Node first  =  null;//第一个节点

    /**
     * 添加节点
     * @param n 需要添加的节点数
     */
    public void addNode(int n){
        if (n < 1){//n 小于1 时不添加
            return;
        }
        Node temp =null;//定义一个辅助节点,帮助构建环形链表
        for (int i = 1; i<=n; i++){//循环添加
           Node node = new Node(i);
           if (i == 1){//添加第一个节点时next指向自己
               first = node;
               first.next = first;//自己指向自己
               temp = first;//辅助节点指向第一个节点
           }else {
               temp.next = node;//添加新节点
               node.next = first;//新节点指向第一个节点
               temp = temp.next;//辅助节点后移(指向新节点)
           }
        }
    }

    public  void  show(){//链表打印
        if (first == null){
            return;
        }
        Node temp = first;
        while (true){
            System.out.println(temp.no);
            if (temp.next == first){
                break;
            }
            temp = temp.next;

        }
    }

    /**
     * 节点出列
     * @param k 约定编号为 k(1<=k<=n)的人从 1 开始报数
     * @param m 数到 m 的人出列
     * @return 最后剩下的节点
     */
    public Node exit(int k,int m){
        //首先将first节点移动到编号为k的节点上
        for (int i=2; i<=k;i++){//k==1就无需移动
            first = first.next;
        }
        Node temp = null;//定义辅助节点,为了指向first的前一个节点

        while (true){
            for (int j = 1;j<=m-1; j++){//从first节点开始移动m-1次
                temp= first;//将first节点赋给temp辅助节点
                first = first.next;//first节点后移
            }
            //这时first节点为出列节点
            first = first.next;//然后first节点后移
            temp.next = first;//temp的next指向后移的first,完成出列

            if (first.next ==first){//最后当first节点指向自己(剩下最后一个)
                return first;//返回first节点
            }
        }
    }
}
//创建节点类
class Node{
     int no;//编号
     Node next;//下一个节点
    public  Node(int no){
        this.no = no;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值