一.简介:
环形链表也叫循环链表(可以是双链表、也可以是单链表),操作原理和单链表差不多,只是最后一个节点不在指向空(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); } }