数据结构与算法-单向环形链表与约瑟夫问题(续思路与代码)

上一篇写的单向环形链表与约瑟夫问题简介和举例,这篇写思路和代码~


目录

3.思路

3.1创建环形链表:

3.2遍历环形链表:

3.3产生出圈序号:

4.代码

4.1在构建环形链表时添加节点:

4.2遍历环形链表:

4.3产生出圈序号:

4.4完整代码:

5.运行结果


3.思路

3.1创建环形链表:

先创建一个节点,有个first变量指向这个节点,这个节点的next也是指向自己。还有个curBoy变量

然后新加一个节点,还有个boy变量。boy变量指向新节点,第一个节点的next指向新节点

然后新节点的next指向第一个节点,curBoy变量指向新节点。成环形了。

再新增一个节点即第三个节点,boy指向这个节点

然后第二个节点的next指向第三个节点,然后curBoy节点指向第三个节点,第三个节点的next指向第一个节点

就形成环形链表了

简单来说就是先创建第一个节点,并使first指向该节点,并形成环形。后面每创建一个新节点,就把该节点加入已有的这个环形链表中。

3.2遍历环形链表:

先让辅助变量curBoy指向first节点,然后通过循环遍历该环形链表,当curBoy.next==first时就遍历完了。

3.3产生出圈序号:

根据用户输入,生成出圈顺序。先设置一个辅助变量helper初始时指向环形链表最后一个节点,小孩报数前先让first和helper移动k-1次也就是移到k所在编号节点。当小孩报数时,first和helper同时移动m-1次(总共移动m下,因为到自己要移动一下,所以除自己之外要移动m-1下),这时就可以将first指向的小孩节点出圈,做法是将first移到下一个(first=first.next),再使helper.next=first。那么原来first指向的节点就没有任何引用,就会被回收。

first后移示意图:

first=first.next示意图:

helper.next=first示意图:

4.代码

4.1在构建环形链表时添加节点:

//添加节点,构建环形链表

public void addBoy(int nums){//看有几个节点

    //校验

    if(nums<1){

        System.out.println("nums值不正确");

        return;

    }

    //辅助变量帮助构建链表

    Boy curBoy=null;

    for(int i=1;i<=nums;i++){

        //创建节点

        Boy boy=new Boy(i);

        //如果是第一个小孩形成环状

        if(i==1){

            first=boy;

            first.setNext(first);//成环

            curBoy=first;//让curBoy指向第一个小孩

        }

        else{

            curBoy.setNext(boy);//构建原来的末尾节点指向新节点的线,就是原来指向first的线变成指向新节点

            boy.setNext(first);//构建新节点指向first的线

            curBoy=boy;//curBoy节点后移到这个新节点

        }

    }

}

4.2遍历环形链表:

//遍历环形链表

public void showBoy(){

    //判断链表是否为空

    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();//后移

    }

}

4.3产生出圈序号:

public void countBoy(int startNo, int countNum, int nums) {

    //先校验

    if (first == null || startNo < 1 || startNo > nums) {

        System.out.println("参数输入有误,请重新输入");

        return;

    }

    //辅助变量帮助出圈

    Boy helper = first;

    while (true) {

        if (helper.getNext() == first) {

            //说明helper指向最后小孩节点了,下一个就是first所在节点

            break;

        }

        helper = helper.getNext();//后移

    }

    //报数前first和helper移动k-1次

    for(int j=0;j<startNo-1;j++){

        first=first.getNext();

        helper=helper.getNext();

    }

    //报数时先移动m-1次然后出圈。直到圈中只有一个节点

    while(true){

        if(helper==first){

            //圈中只有一个节点

            break;

        }

        //first和helper同时移动countNum-1次

        for(int j=0;j<countNum-1;j++){

            first=first.getNext();

            helper=helper.getNext();

        }

        //此时first指向的节点是要出圈的节点

        System.out.printf("小孩 %d 出圈 \n",first.getNo());

        //将小孩节点出圈

        first=first.getNext();//first移到出圈的下一个节点

        helper.setNext(first);//helper的下一个指向first

    }

    System.out.printf("最后留在圈中的小孩编号 %d \n",helper.getNo());

}

4.4完整代码:

package com.xjj.linkedlist;



public class Josephu {

    public static void main(String[] args) {

        //测试构建环形链表与遍历

        CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();

        circleSingleLinkedList.addBoy(5);//加入5个

        circleSingleLinkedList.showBoy();

        //测试出圈顺序是否正确

        circleSingleLinkedList.countBoy(1,2,5);//出圈顺序为2-4-1-5-3

    }

}



//创建环形链表(单向)

class CircleSingleLinkedList {

    //创建first节点,首先不知道谁是第一个小孩所以先没有编号,设为-1

    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++) {

            //创建节点

            Boy boy = new Boy(i);

            //如果是第一个小孩形成环状

            if (i == 1) {

                first = boy;

                first.setNext(first);//成环

                curBoy = first;//让curBoy指向第一个小孩

            } else {

                curBoy.setNext(boy);//构建原来的末尾节点指向新节点的线,就是原来指向first的线变成指向新节点

                boy.setNext(first);//构建新节点指向first的线

                curBoy = boy;//curBoy节点后移到这个新节点

            }

        }

    }



    //遍历环形链表

    public void showBoy() {

        //判断链表是否为空

        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 startNo  表示从第几个小孩开始数

     * @param countNum 表示数几下

     * @param nums     表示最初有多少小孩在圈中

     */

    public void countBoy(int startNo, int countNum, int nums) {

        //先校验

        if (first == null || startNo < 1 || startNo > nums) {

            System.out.println("参数输入有误,请重新输入");

            return;

        }

        //辅助变量帮助出圈

        Boy helper = first;

        while (true) {

            if (helper.getNext() == first) {

                //说明helper指向最后小孩节点了,下一个就是first所在节点

                break;

            }

            helper = helper.getNext();//后移

        }

        //报数前first和helper移动k-1次

        for(int j=0;j<startNo-1;j++){

            first=first.getNext();

            helper=helper.getNext();

        }

        //报数时先移动m-1次然后出圈。直到圈中只有一个节点

        while(true){

            if(helper==first){

                //圈中只有一个节点

                break;

            }

            //first和helper同时移动countNum-1次

            for(int j=0;j<countNum-1;j++){

                first=first.getNext();

                helper=helper.getNext();

            }

            //此时first指向的节点是要出圈的节点

            System.out.printf("小孩 %d 出圈 \n",first.getNo());

            //将小孩节点出圈

            first=first.getNext();//first移到出圈的下一个节点

            helper.setNext(first);//helper的下一个指向first

        }

        System.out.printf("最后留在圈中的小孩编号 %d \n",helper.getNo());

    }

}



//Boy类表示节点

class Boy {

    private int no;//编号

    private Boy next;//指向下一个节点



    public Boy(int no) {

        this.no = no;

    }



    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;

    }

}

5.运行结果

测试的是k=1,n=5,m=2的情况。理论出圈顺序为2-4-1-5-3。

成功实现


加油加油^_^

  • 25
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值