数据结构和算法之环形链表

约瑟夫环问题:

思想: 因为是循环,所以我们可以考虑环形链表,当然还可以用数组取模来进行实现

实现的步骤:

1·首先先要构成一个环形链表

  • 1·1:先创建一个新的节点,并让first变量指向该节点,并先让自身形成环形

  • 1.2:将后面产生的心得节点假如环形链表中即可

2·考虑怎么遍历环形链表:采用一个辅助指针

  • 2.1:采用一个辅助指针cur让其遍历

  • 2.2:当cur.next==first的时候,环形链表就是遍历完了

3·小孩出圈的一个思路:

  • 3.1:再使用一个辅助指针helper让其指向环形链表的最后一个元素,也就是环形链表第一个元素的前一个元素,相当于直到了删除节点的前驱;helper(环形链表的最后一个元素),first(环形链表的第一个元素)

  • 3.2:first和helper同时走,当first指向的是要出圈的节点,那么久让first=first.next;然后将helper.next=first;也就相当于先将要出圈的节点在环形链表中删除即可

具体代码如下所示:

//创建节点类:Node
class Node{
    public int no;//编号
    public Node next;//一个节点的next域,默认为null

    public Node(int no) {
        this.no = no;
    }
}

//创建一个单向的环形链表:
class CircleSingleList{
    //创建一个first节点,当前没有编号
    public Node first=new Node(-1);
    public void addNode(int nums){//表示你自己要创建多少个节点
        //进行一个nums校验:
        if(nums<1){
            System.out.println("nums的值不正确");
            return;
        }

        //否则适使用一个循环 将其单向循环链表做成12345......等等的链表:
        //因为要用到辅助指针,所以先将辅助指针进行定义
        Node curBoy=null;
        for (int i = 1; i <= nums; i++) {
            //根据编号创建节点
            Node boy=new Node(i);
            //如果是第一个节点,将first指针指向该节点:
            //1·将第一个节点自身也构建成一个环状
            if(i==1){
                first=boy;
                first.next=first;//将第一个节点自身构成环装
                curBoy=first;//因为first是不能动的,所以用curBoy有关,用其构造单向循环链表
            }else {
                curBoy.next=boy;
                boy.next=first;
                curBoy=boy;
            }
        }
    }

    //遍历啊当前环形链表:也要使用一个辅助变量将其循环遍历即可
    public void showCircleSingleList(){
        //判断单链表是否为空
        if(first==null){
            System.out.println("单向循环链表为空");
            return;
        }

        //创建一个辅助变量遍历循环单链表,因为first是不能变的
        Node curBoy=first;
        while(true){
            System.out.println("显示当前小孩的编号:"+curBoy.no);
            if(curBoy.next==first){//说明单向循环链表遍历完了
                break;
            }
            curBoy=curBoy.next;//将curBoy进行遍历往后移动

        }
    }

    //根据用户的输入,计算小孩出圈的顺序
    /*
    * startNum:表示第几个小孩开始数
    * countNum:表示数几下
    * nums:表示刚开始有多少小孩在圈里*/
    public void countNode(int startNum,int countNum,int nums){
        //先对用户输入的数据进行检验
        /*
        * first==null说明这个循环链表为空,没有意义
        * startNum<1:说明不可能从第0个孩子开始,因为么有第0个孩子
        * startNum>nums:说明不可以超过nums个小孩,本来就只有5个小孩,非要从第六个小孩开始*/
        if(first==null||startNum<1||startNum>nums){
            System.out.println("参数输入有误,请重新输入");
            return;
        }

        //创建辅助指针,帮助出圈
        Node helper=first;
        //先让helper指向循环单链表的最后一个节点
        while(true){
            if(helper.next==first){
                break;
            }
            helper=helper.next;
        }//跳出循环的时候就是,helper在循环单链表最后一个位置

        //报数前,得先让first和helper走startNum-1步,走到用户让开始的地方
        for(int j=0;j<startNum-1;j++){
            first=first.next;
            helper=helper.next;
        }
        //出圈时,让first和helper先走k-1步也就是(countNum-1步)
        //这是一个循环的操作:
        while(true){
            if(helper==first) {//说明圈中只有一个人,直接出圈即可
                break;
            }

            //让first和helper同时走countNum-1步
            for (int i = 0; i <countNum-1 ; i++) {
                first=first.next;
                helper=helper.next;
            }//这时候first指向的就是要出圈的小孩
            System.out.println("小孩出圈的序号为:"+first.no);

            //这时将first指向的小孩出圈
            first=first.next;
            helper.next=first;
        }
        System.out.println("最后留在圈中的小孩序号:"+first.no);
    }
}
public class Josepfu {
    public static void main(String[] args) {
        //测试构建环形链表是否成功,遍历也是否成功
        CircleSingleList circleSingleList=new CircleSingleList();//默认是无参构造器
        circleSingleList.addNode(5);
        circleSingleList.showCircleSingleList();

        //测试小孩出圈的顺序:
        circleSingleList.countNode(1,2,5);
    }
}

运行结果如下所示:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值