JAVA 使用单向环形链表解决约瑟夫问题

本文介绍了如何使用JAVA通过单向环形链表解决约瑟夫问题。详细阐述了创建环形链表、遍历链表以及实现约瑟夫问题的步骤,并给出了测试结果,展示出圈的小孩编号。
摘要由CSDN通过智能技术生成

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

nums = 10 , 即有10个人

start = 2, 从第二个人开始报数

count = 3, 3

具体实现如下:

1、创建一个小孩节点对象

 class Child{
        private int no;
        private Child next;

        public Child(int no){
            this.no  = no;
        }

        public void setNo(int no) {
            this.no = no;
        }

        public int getNo() {
            return no;
        }

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

        public Child getNext() {
            return next;
        }
    }

2、构建一个单向环形链表

1)先创建第一个节点, first 指向该节点

2)异常判断:判断传的小孩个数是否大于1

3)创建当前节点cur,并使用for循环依次创建链表的各个节点。并把该节点,加入到已有的环形链表中即可.

     当i=1时,first指向对应编号为1的节点。并设置first的下个节点为自己(形成环形链表),设置当前节点cur指向first。

     当i!=1时,直接在已有节点后追加对应i的节点,设置当前节点cur的下个节点指向对应i的节点。设置对应i的节点的下个节点为first(形成环形链表).最后再设置当前节点cur为对应i的节点。

class CircleSingleLinedList{
    Child first = new Child(-1);
    //添加小孩节点,形成环形链表
    public void addChild(int nums){
        if(nums<1){
            System.out.println("小孩个数不正确,请重新输入");
            return;
        }

        Child curChild = null;
        for(int i=1;i<=nums;i++){
            Child child = new Child(i);
            if(i==1){
                first = child;
                first.setNext(first);
                curChild = first;
            }else {
                curChild.setNext(child);
                child.setNext(first);
                curChild = child;
            }
        }
    }
}

3、遍历环形链表

1)先判断链表是否为空,如果为空则为空链表,直接return。

2)  然后创建一个辅助指针(变量) curChild,指向first节点。

3)后通过一个while循环遍历 该环形链表。当curChild.next  == first 时退出循环。

//遍历链表
     public void showChild(){
         if(first == null){
             System.out.println("没有小孩~~~~~~");
             return;
         }
         Child curChild = first;
         while (true){
             System.out.printf("小孩的编号 %d\n",curChild.getNo());
             if(curChild.getNext() == first){
                 break;
             }
             curChild = curChild.getNext();
         }
     }

4、约瑟夫问题实现

1)异常情况处理
      头结点为空时return
      开始节点Start不在1到链表长度之间时return
      每次数几个数(步长)<1时return

2)创建头节点head、尾节点对象last。分别指向first

3)  使用while循环,当last的下个节点为head时退出循环,并为last节点赋值。
4)for循环让头结点head,last尾结点移动start-1次
5)while循环,链表长度不等于0时,使用for循环移动头结点head,尾结点last ,步长size-1次
6)  第5步,得到出圈小孩编号。接着删除头结点,步骤如下:
     先保存头结点的下一个结点到nextnode
     然后将尾结点的下一个结点指向nextnode
     然后设置头结点的下一个结点为空
     接着更新链表的长度
     最后设置头结点指向nextnode

 //根据用户的输入,计算出小孩出圈的顺序
     public void countChild(int start,int size,int nums) {
         Child head = first;
         Child last = first;
         if (head == null) {
             return;
         }
         if (start < 1 || start > nums||size < 1) {
             System.out.println("请输入正确的参数~~");
             return;
         }

         while (true){
             if(last.getNext() == head){
                 break;
             }
             last = last.getNext();
         }
         for (int i = 0; i < start - 1; i++) {
             head = head.getNext();
             last = last.getNext();
         }

         while (nums != 0) {
             for (int i = 0; i < size - 1; i++) {
                 head = head.getNext();
                 last = last.getNext();
             }
             System.out.printf("编号为%d的小孩出圈\n", head.getNo());

             Child nextChild = head.getNext();
             last.setNext(nextChild);
             head.setNext(null);
             nums--;
             head = nextChild;
         }

         System.out.printf("最后留在圈中的小孩是%d",head.getNo());
     }

5、测试类

public class Josephu {
    public static void main(String[] args) {
        CircleSingleLinedList childLinklist = new CircleSingleLinedList();
        childLinklist.addChild(10);
       // childLinklist.showChild();
        childLinklist.countChild(2,3,10);//出圈的顺序4->7->10->3->8->2->9->6->1->5

    }

    }

输出结果:

编号为4的小孩出圈
编号为7的小孩出圈
编号为10的小孩出圈
编号为3的小孩出圈
编号为8的小孩出圈
编号为2的小孩出圈
编号为9的小孩出圈
编号为6的小孩出圈
编号为1的小孩出圈
编号为5的小孩出圈
最后留在圈中的小孩是5

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值