ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Java学习——数据结构之约瑟夫问题

2021-11-30 12:00:46  阅读:146  来源: 互联网

标签:Boy 结点 Java 约瑟夫 链表 next 数据结构 节点 first


约瑟夫 问题描述:设编号为1、2、3... ...n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m的那个人先出列,他的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人都出列为止,由此产生一个出队编号的序列,求此序列。

 

算法思路:

先构成一个有n个结点的单循环链表,然后由k结点起从1开始计数,计到m时,保存对应节点的编号,并将节点从链表中删除,然后再从被删除结点的下一个结点又从1开始计数,直到最后一个结点从链表删除。

代码分析:

1.构建环形链表:

  • 创建第一个结点,并让first指向该结点,并将该节点的next域指向自己形成环形。

  • 每创建一个新节点,就把该节点加入到已有的环形链表中

     

2.遍历环形链表

  • 定义一个辅助变量curBoy ,指向first节点

  • 通过while循环找到最后一个加入环形链表的结点,并将curBoy指向这个节点,即:curBoy.next==first

  • (添加这个辅助变量的目的是保存first的前趋,便于删除报数完毕后first指向的结点)

3.报数

  • 每一轮报数时,使用for循环m次,每循环一次,first和curBoy同时往下一位报数的人的方向移动一次。

  • 当循环完毕m次时,保存first的编号,然后删除first结点:

    • int n=first.no

    • first=first.next;

    • curBoy.next=first

  • 每一轮报数结束,使用数组存储出列的编号,当圈中只剩下一个人时,直接将其编号添加至数组,最后依次打印数组的值即为出队编号的序列。

     

代码实现

结点:

//创建一个Boy类,表示一个节点
class Boy{
    private int no;  //编号
    private Boy next; //指向下一个结点,默认null

    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;
    }
}

链表:

//创建一个环形的单向链表
class CircleLinkedList{
    //创建一个first结点 当前没有编号
    private Boy first = null;
    //添加小孩结点 构建一个环形的链表
    public void addBoy(int nums){
        //nums代表加入小孩的个数
        if(nums<1){
            System.out.println("nums的值不正确,添加失败");
            return;
        }
        Boy curBoy = null; //辅助变量,帮助创建环形链表
        //使用for循环来创建环形链表
        for(int i=1;i<=nums;i++)
        {
            Boy boy = new Boy(i);
            //如果是第一个小孩
            if(i==1){
                first=boy;
                first.setNext(first); //一个小孩也可以构成一个环状
                curBoy=first;
            }else {
                curBoy.setNext(boy);
                curBoy=boy;
                boy.setNext(first);
            }
        }

    }
    //遍历当前的环形链表
    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(); //curBoy后移直到其next指向first
        }
    }

    //根据用户的输入,计算出小孩的出圈顺序
    /*
        startNo 开始的小孩的编号
        countNo 表示数几下
        nums    表示最初的小孩的个数
     */
    public int[] countBoy(int startNo,int countNo,int nums){
        Boy boyFirst = first;
        for (int i=1;i<startNo;i++)
            boyFirst=boyFirst.getNext();  //遍历到开始报数的小孩
        Boy pre=boyFirst; //记录每一轮开始报数的前一个小孩,也就是每一圈的最后一个小孩
        for (int i=1;i<nums;i++)
            pre = pre.getNext();

        int[] boys = new int[nums]; //记录出圈的编号序列
        for (int j=0;j<nums;j++) {
            for (int i = 0; i < countNo - 1; i++) {                               //下一圈的开始和最后一起后移,一直移到出圈的小孩
                pre = pre.getNext();
                boyFirst = boyFirst.getNext();
            }

            boys[j] = boyFirst.getNo();//记录出圈的小孩编号

            boyFirst=boyFirst.getNext();//删除出圈小孩的结点
            pre.setNext(boyFirst);
        }
        return boys;

    }
}

 

标签:Boy,结点,Java,约瑟夫,链表,next,数据结构,节点,first
来源: https://www.cnblogs.com/xjl181016/p/15623576.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有