涉及 创建单向环形链表、添加节点、遍历节点、节点出圈 功能
package com.atguigu.linkedlist;/*** 约瑟夫问题* 单向环形链表** @author Dxkstart* @create 2021-10-03-17:10*/public class Josepfu {public static void main(String[] args) {//测试CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();circleSingleLinkedList.addBoy(5);//加入5个小孩节点circleSingleLinkedList.showBoy();//测试小孩出圈circleSingleLinkedList.countBoy(1,2,5);}}//创建一个Boy类,表示一个节点class Boy {private int no;private Boy next;public Boy(int no) {this.no = no;}public int getNo() {return no;}public void setNo(int no) {this.no = no;}public Boy getNext() {return next;}public void setNext(Boy next) {this.next = next;}}//创建一个单向的环形链表class CircleSingleLinkedList {//创建一个first节点,当前没有编号private Boy first = null;public Boy getFist() {return first;}//添加小孩节点,构建成一个环形的链表public void addBoy(int nums) {//nums 做一个数据校验if (nums < 1) {System.out.println("nums的值不正确");return;}//中间变量指针Boy curBoy = null;//使用for来创建我们的环形链表for (int i = 1; i <= nums; i++) {//Boy boy = new Boy(i);if (i == 1) {first = boy;first.setNext(first);//构成环,自己指向自己curBoy = first;} else {curBoy.setNext(boy);//中间变量指针,指向新节点,打开环boy.setNext(first);//新的节点指向第一个节点,构成环curBoy = boy;//中间变量指针,指向新节点}}}//遍历当前环形链表public void showBoy() {//判断是否为空if (first == null) {System.out.println("链表为空");return;}//因为first不能动,因此我们仍然使用一个辅助指针完成遍历Boy curBoy = first;while (true) {System.out.printf("小孩的编号为:%d \n", curBoy.getNo());if (curBoy.getNext() == first) {//说明已经遍历完毕break;}curBoy = curBoy.getNext();//curBoy后移}}//根据用户的输入,计算出小孩的出圈顺序/*** @param startNo 表示从第几个小孩开始数数* @param countNum 表示每次数几下* @param nums 表示最初有几个小孩在圈中*/public void countBoy(int startNo, int countNum, int nums) {//先对数据进行校验if (first == null || startNo < 1 || startNo > nums) {System.out.println("参数输入有误,请重新输入");return;}//创建辅助指针Boy helper = first;//事先将辅助指针helper指向最后一个节点while (true) {if (helper.getNext() == first) {break;}helper = helper.getNext();}//小孩报数前,先让 first 和 helper 移动k-1次(即first移动到第一个要报数的小孩那里)for (int i = 0; i < startNo-1; i++) {first = first.getNext();helper = helper.getNext();}//开始报数//当小孩报数时,让first 和 helper指针同时移动m-1次,然后出圈//这里是一个循环操作,直到权值只有一个节点while (true){if (helper == first){//此时圈中只有一个人System.out.println("结束");break;}//让first 和 helper 指针同时移动 countNum-1 次for (int i = 0; i < countNum-1; i++) {first = first.getNext();helper = helper.getNext();}//这时first指向的节点,就是延出圈的小孩节点System.out.printf("小孩%d出圈 \n" , first.getNo());//将first指向的节点出圈first = first.getNext();helper.setNext(first);}System.out.printf("最后留在圈中的小孩编号为%d \n",first.getNo());}}
