数据结构与算法分析----环形链表之约瑟夫问题的解决

环形链表概述

循环链表是另一种形式的链式存储结构。它的特点是表中最后一个结点的指针域指向头结点,整个链表形成一个环。

环形链表的简单实现

节点的设计:
在这里插入图片描述
和普通的单链表一样

链表的功能实现类:
这里仅简单的实现一个环形链表,add方法接受一个整形的参数,用于设置链表有几个节点,用for循环,依次创建节点,节点名称固定,标号按照从1到整形参数k来设置
在这里插入图片描述在每次创建新节点后,将其加入链表,如果链表中没有数据,则,将第一个节点设置为第一个结点,即first,并令first指向自己,当链表中有数据,则插入到第一个节点和倒数第一个节点的中间,并更新辅助接点temp,使其指向被插入的节点

链表遍历:
首先令temp指向first,然后进行遍历,遍历结束的判决条件是temp==first
在这里插入图片描述

约瑟夫问题的解决

此方法接收两个参数,一个代表从第几个学生开始报数,一个代表每一次的报数需要报到几
整体的思路是:首先为了方便出列,通过遍历,将temp指向倒数第一个节点,在遍历的过程中顺便统计一下共有多少人,然后此时temp指向了倒数第一个节点,并得到了共多少个学生,此时先判断传入的参数是否正确。正确后,根据要从第几个学生开始报数来把temp和first移动对应的次数,然后根据每次报几下来进行遍历出列,链表中仅剩一个人的判决条件是temp==first

//    约瑟夫问题的解决
//    m:从第几个学生开始报数 k:每一次需要报几下
    public void JosephuDemo(int m,int k){
    
    
        if (first==null){
    
    
            System.out.println("无数据");
            return;
        }
//        初始化temp
        temp=first;
        int n=1;  //n表示共有多少学生
        while (temp.next!=first){
    
      //首先通过遍历使temp指向环链表"尾",即first的上一个节点。此举是为了方便移除学生
//            在遍历的时候顺便用n统计一下共有多少学生
//            注意n的初始值需要是1,因为这里while循环的次数仅仅是一个移动的次数,并不是节点的个数
//            就好比是线段,有头和尾两个点,但是从头到尾只需要移动一次
            n++;
            temp=temp.next;
        }
//        得到n后,判断数据输入是否正确
        if (m>n||m<1||k<1){
    
    
            System.out.println("数据出错");
            return;
        }
//        m表示从第几个学生开始数,所以在开始前,需要先将temp和first移动几次进行初始化
//        为什么是m-1?和前面n那里一样,此处m表示的是"个数",是从第几个学生开始数,这里for循环的次数仅仅是一个移动的次数
        for (int i = 0; i < m-1; i++) {
    
    
//            移动
            temp=temp.next;
            first=first.next;
        }
        int p=1;  //用于记录出列的学生是第几次出列
        while (temp!=first){
    
       //环链表中只剩一个学生的判别条件是temp==first,因为当链中数据大于1个时,temp和first一定是相邻的,并不是相同的
            for (int i = 0; i < k-1; i++) {
    
    
//          为什么是k-1?和前面m同理,k表示的是"个数",这里for循环需要表示的是一个移动的次数
                temp=temp.next;
                first=first.next;
            }
            System.out.println("第"+p+"个出列的是"+first);
            first=first.next;  //找到后,将first节点跳到要出列节点的下一个节点,方便后续的遍历出列和判断
            temp.next=first;   //此处执行前,temp和first中间相隔一个节点,,此节点就是出列的节点,删除此节点,
            p++;  //更新p值
        }
        System.out.println("幸存者是"+first);
    }

测试

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_45821251/article/details/120054123