JAVA环形链表--约瑟夫问题

摘要:在这个问题中,N个人围成一圈,从第一个人开始报数,每数到第M个人,该人就必须离开(或被杀掉),然后由下一个人重新开始报数,直到最后只剩下一个人。这个问题通常被称为约瑟夫环或“丢手绢问题”,并以弗拉维奥·约瑟夫斯(Flavius Josephus)命名,他是一位1世纪的犹太历史学家。

在Java中又该如何解决这个问题呢?创建节点--->创建环形链表--->计算出圈顺序。

1.先创建一个Boy类(链表节点)

class Boy{
    private int num;
    private Boy next;//下一个节点,默认为null

    public Boy(int num) {
        this.num = num;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }

    public Boy getNext() {
        return next;
    }

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

 2.创建一个环形链表

//创建环形链表
class CircleSingleLinkedList{
    //创建first节点
    private Boy first = null;//也可以是 =new Boy(-1),只要是让第一个节点不存在就可以
    //添加节点
    public void addBoy(int nums){//nums代表圈内小孩的个数
        if (nums < 1){
            System.out.println("输入的小孩不对");
            return;
        }
        //定义临时变量
        Boy curBoy = null;//辅助指针
        for (int i = 1; i <= nums; i++) {
            Boy boy = new Boy(i);//每循环一次根据序号创建一个Boy节点
            if (i == 1){
                first = boy;
                first.setNext(first);
                curBoy = first;//curBoy指向第一个小孩
            }else {
                curBoy.setNext(boy);
                boy.setNext(first);
               curBoy = boy;//curBoy指向这个boy
            }
        }
    }

3.计算出圈顺序

思路:

 

 

 //根据用户的输入,计算出小孩出圈顺序
    /*
    * startNo:表示从第几个小孩开始数数
    * countNum 表示数几下
    * nums 表示最初有多少小孩在圈中
    * */
    public void countBoy(int startNo, int countNum,int nums){
        //判断链表是否为空
        if (first == null || startNo > nums || startNo < 1){
            System.out.println("不符合");
            return;
        }
        //创建一个辅助指针helper,事先指向环形链表的最后一个节点
        Boy helper = first;
        while (true){
            if (helper.getNext() == first){//当helper的next指向了frist就说明到最后了
                break;
            }
            helper = helper.getNext();
        }

        //报数前,让first和helper移动startNo -1次
        for (int i = 0; i < startNo - 1; i++) {
            first = first.getNext();
            helper = helper.getNext();
        }

        //报数时,让first和helper同时移动countNum - 1次
      while (true){
          if (helper == first){//说明圈中只有一个节点
              break;
          }

          for (int i = 0; i < countNum - 1; i++) {
              first = first.getNext();
              helper = helper.getNext();

          }
          //这时候first指向的节点就是要出圈的节点
          System.out.println("出圈的节点是" + first.getNum());
          //这时侯first指向的就是要删除的节点
          first = first.getNext();
         helper.setNext(first);
      }
        System.out.println("最后留下了的节点" + first.getNum());
    }

补充 : //这时侯first指向的就是要删除的节点
          first = first.getNext();
         helper.setNext(first);这一步的图解:

4.测试

/*
* 约瑟夫问题--环形链表
* */
public class Josepfu {
    public static void main(String[] args) {

        CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
        circleSingleLinkedList.addBoy(5);
        circleSingleLinkedList.countBoy(1,2,5);//第1个开始数,数2下,最初有5个小孩在链表中

       
    }
}

  • 14
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值