一.简介:
环形链表也叫循环链表(可以是双链表、也可以是单链表),操作原理和单链表差不多,只是最后一个节点不在指向空(null)而是头(head),这里以单链表举例:


二.代码实现约瑟夫问题

1)构建一个单向的环形链表思路
- 先创建第一个节点,让first指向该节点,并形成环形
- 后面当我们每创建一个新的节点,就把该节点加入到已有的环形链表中即可。
2)遍历环形链表
- 先让一个辅助指针(变量)curBoy,指向first节点
- 然后通过一个while循环遍历该环形链表即可,curBoy.next == first结束
5. 约瑟夫问题小孩出圈的思路分析

1.定义孩子类型
public class Boy {
private int no;//编号
private Boy next;//指向下一个节点
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;
}
public Boy(int no) {
this.no = no;
}
}
2.定义循环链表
public class CircleSingleLinkedList {
private Boy first = new Boy(-1);
//添加小孩节点,构建一个环形链表
public void addBoy(int nums){
//参数校验
if (nums<1){
System.out.println("nums的值不正确");
return;
}
Boy curBoy = null;//辅助指针
for (int i = 1; i <= nums; i++) {//使用for循环创建环形链表
//根据编号创建小孩节点
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.getNext()==null){
System.out.println("环形链表为空!!!");
return;
}
Boy curBoy = first;
while (true){
System.out.printf("小孩的编号:%d
",curBoy.getNo());
if (curBoy.getNext()==first){//遍历完毕
break;
}
curBoy=curBoy.getNext();//指针后移
}
}
/*根据用户的输入计算出小孩出圈的顺序*/
/**
*
* @description:TODO
* @params:1.第几个小孩开始2.表示数几下,3.最初有多少个小孩
* @return:
* @author: sxw
* @time: 2020/3/11 20:32
*/
public void countBoy(int startNo,int countNum,int nums){
//参数校验
if (first == null||startNo<0||startNo>nums){
System.out.println("输入参数有误,请重新输入");
return;
}
Boy helper = first;
while (true){//将指针指向最后一个节点
if (helper.getNext()==first){
break;
}
helper=helper.getNext();
}
//小孩报数,将first和helper移动K-1次
for (int i = 0; i <startNo-1 ; i++) {
first=first.getNext();
helper=helper.getNext();
}
//报数时将first和helper同时移动m-1次,然后出圈
//当圈内只有一个节点时循环结束
while (true){
if (helper==first){//什么时候结束圈内只有一个节点
break;
}
//让first和helper同时移动countNum次
for (int i = 0; i <countNum-1 ; i++) {
first=first.getNext();
helper=helper.getNext();
}
//这时first指向的是小孩出圈的节点
System.out.printf("小孩%d出圈
",first.getNo());
//first指向的小孩出圈
first=first.getNext();
helper.setNext(first);
}
System.out.printf("最后留着圈中小孩编号%d
",first.getNo());
}
}
3.进行测试
public class JosepFu {
public static void main(String[] args) {
//测试构建和遍历环形链表是否ok
CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
circleSingleLinkedList.addBoy(5);
circleSingleLinkedList.showBoy();
/*测试小孩出圈*/
circleSingleLinkedList.countBoy(1,2,5);
}
}