ICode9

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

单向环形链表——解决约瑟夫问题Java

2022-01-09 09:06:23  阅读:151  来源: 互联网

标签:约瑟夫 Java help cur next 链表 指针 first


Josephu问题

Josephu问题为:
设编号为1, 2, …n的n个人围坐一圈,约定编号为k (1<=k<=n)的人从1开始报数,数到m的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。

思路:

  • 我们不妨创建一个单向环形链表来模拟这种情况,根据小孩的出列断开不同的节点,连接新的节点进行模拟。

代码:

package 链表;

public class JosePhu问题 {
    public static void main(String[] args) {
        CircleLinkedList circleLinkedList = new CircleLinkedList();
        circleLinkedList.addBoy(5);   //此时环形链表有五个节点
        circleLinkedList.list();
        circleLinkedList.countBoy(1,2,5);
    }

}

class CircleLinkedList{
    private Boy first = null;    //初始头节点

    //构建指定长度的环形链表
    public void addBoy(int num){
        Boy cur = null;  //用来遍历的辅助指针
        for(int i=1;i<=num;i++){
            Boy boy = new Boy(i);
            if(i==1){
                //第一次构建需要自身指向自身
                first = boy;
                first.next = first;
                cur = first;
            }
            else{
                cur.next = boy;   //将新建立的节点加入环形链表中,此时cur的位置就是原先创建的环形链表的尾端
                boy.next = first; //将添加进来的新节点的尾部指向头节点,形成环状
                cur = cur.next;  //cur每次要移动到尾部
            }
        }
    }

    //按照添加顺序显示环形链表
    public void list(){
        if(first==null){
            System.out.println("环形链表为空");
            return;
        }
        Boy cur = first;  //用来遍历的临时指针
        while(true){
            System.out.println(cur.num);  //先打印
            if(cur.next==first){  //如果其next指向头指针,则代表遍历完全
                return;
            }
            cur = cur.next;
        }
    }
/*
* startNo  表示从第几个小孩开始数数
* countNum 表示数几下
* nums     表示最初有多少小孩在里面
* 这个是用来解决约瑟夫问题的方法,即指定小孩人数,第一次报数从哪个小孩开始,每数到几让谁出来 后,我们使用环形链表来模拟出队顺序
* */
    public void countBoy(int startNo,int countNum,int nums){
        /*
        * 其实可以不用两次循环,使用一次循环来解决,即first向前移动时,help跟着移动,只不过移动的要比first少1即可;
        * 但是这样的话对于countNum为0时则不行
        * */
        Boy help = first;  //辅助指针,指向头指针的前一个位置
        /*因为我们下面是设置头指针直接移动到我们要出队的节点,而又由于我们是一个单向环形队列,所以头指针位置要出队,那么我们
         为了保存头指针位置,只能从头指针的前一个位置得到,所以我们设置辅助指针的目的就是为了通过其的next指针来得到删去的
        头指针位置!!!! 所以其实这个也可以不设置,不过设置了会更加清晰*/

        //先将辅助指针移动到尾部,因此此时头指针在头部,所以刚好形成前后关系
        while(true){
            if(help.next==first){
                break;
            }
            help = help.next;
        }

        //因此从第startNo个小孩开始报数,所以头指针的实际位置需要改变
        for (int i=0;i<startNo-1;i++){
            first = first.next;
            help = help.next;   //help是头指针的前一个,所以也跟着动
        }

        //模拟报数出队,直到全部出完
        while(true){
            for (int i=0;i<countNum-1;i++){  //先报数,即头指针先移动到指定要出队的节点的位置
                first = first.next;
                help = help.next;  //辅助指针跟着移动
            }
            System.out.println(first.num);  //找到要出队的了
            if(help==first){   //如果两个指针重合,则一定代表就剩下一个了,因为一个指针的下一个指针指向自己了!
                break;
            }
            first = first.next;  //将头指针此时指向的位置删除,并指向自己原先位置指向的的下一个位置
            help.next = first;  //将被删除的节点的上一个节点的next指向设置为删除位置的下一个位置 , 这样才起到删除作用
        }
    }
}

class Boy{
    int num;
    Boy next;

    public Boy(int num) {
        this.num = num;
    }

    public Boy() {
    }

}

标签:约瑟夫,Java,help,cur,next,链表,指针,first
来源: https://blog.csdn.net/xiangguang_fight/article/details/122389781

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

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

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

ICode9版权所有