单向环形链表介绍

单向环形链表可以理解为单链表首尾相连的链表.

创建环形链表

  • 构建一个单向环形链表思路
    • 先创建第一个节点,让first指向该节点,并形成环形 first.next = first
    • 添加辅助指针curBoy = first 待添加的节点为boy
    • 添加节点 curBoy.next = boy;boy.next = first;(成环) curBoy = boy;(指向下一个节点)
  • 遍历
    • 先让一个辅助针织curBoy指向first节点
    • 然后通过while循环遍历该环形链表即可,结束条件为:curBoy.next == first

josephu问题

  • 提示:用一个不带头结点的循环链表来处理josephu问题:先构建一个有n和节点的单循环链表,然后由k节点起从1开始计数,计数到m,对应节点从链表中删除,然后被删除的下一个节点又从1开始计数,知道最后一个节点从链表中删除.

  • 需要创建一个辅助指针helper,事先应该指向环形链表的最后一个节点 (遍历实现 结束条件 helper.next = first)

  • 报数前,先让first和helper移动k-1次 (这是题中的从第k个人开始报数)

  • 当小孩报数时,让first和helper指针同时移动m-1次

  • 这时就将first指向的小孩出圈.

    • first = first.next;
    • helper.next = first

代码实现

public class circleLinkedList {
    public static void main(String[] args) {

        CircleLinked circleLinked = new CircleLinked();
        // 测试添加
        circleLinked.add(5);
        circleLinked.list();
        System.out.println("测试出圈----------------");
        //测试出圈
        circleLinked.countBoy(5,1,2);
    }
}

//循环链表
class CircleLinked{
    //第一个节点 设置为null 是因为下面会进行复制
    private Boy first = null;

    /**
     *
     * @param num 向环形链表添加的节点数目
     */
    public void add(int num){
        if (num < 1){
            System.out.println("输入无效数据!!");
            return;
        }
        Boy curBoy = null;  // 添加辅助指针
        for (int i = 1;i <= num;i++){
            Boy boy = new Boy(i);
            //第一个节点
            if (first == null){
                first = boy;
                first.setNext(first);
                curBoy = first;  //让辅助指针指向first
            }else {
                curBoy.setNext(boy);
                boy.setNext(first);  //尾节点指向头结点,成环
                curBoy = boy;  //指向下一个节点
            }
        }
    }
    //显示链表
    public void list(){
        if (first == 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();
        }
    }

    /**
     *
     * @param n 总共有多少和小孩
     * @param k 从第几个人开始报数
     * @param m 数几下
     */
    public void countBoy(int n,int k,int m){
        //校验数据
        if (first == null || k < 1 || k > n){
            System.out.println("数据有误");
            return;
        }
        Boy helper = first;
        //helper指向环形链表的最后一个节点
        while (true){
            if (helper.getNext() == first){
                break;
            }
            helper = helper.getNext();
        }
        ///小孩报数前,先让 first 和 helper 移动 k - 1 次
        for (int i = 0;i < k-1;i++){
            first = first.getNext();
            helper = helper.getNext();
        }
        while (true){
            if (helper == first){ //圈中只有一个节点
                break;
            }

            //first 和 helper 移动m-1此
            for (int i = 0;i < m-1;i++){
                first = first.getNext();
                helper = helper.getNext();
            }
            //出圈小孩
            System.out.printf("出圈编号为%d\n",first.getNo());
            first = first.getNext();
            helper.setNext(first);
        }
        System.out.printf("出圈编号为%d\n",first.getNo());
    }
}

class Boy{
    private int no;
    private Boy next;

    public Boy(int no){
        this.no = no;
    }
    public int getNo() {
        return no;
    }

    public Boy getNext() {
        return next;
    }

    public void setNext(Boy next) {
        this.next = next;
    }
}
02-14 04:27