环形链表

一.简介:

环形链表也叫循环链表(可以是双链表、也可以是单链表),操作原理和单链表差不多,只是最后一个节点不在指向空(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\n",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出圈\n",first.getNo());
            //first指向的小孩出圈
            first=first.getNext();
            helper.setNext(first);
        }
        System.out.printf("最后留着圈中小孩编号%d\n",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);

    }
}

  

 

posted @ 2020-04-21 21:12  苏先生139  阅读(506)  评论(0编辑  收藏  举报