• 数据结构之单向环形列表解决josef问题


    1.定义节点类

       该节点类中只有孩子的编号,以及指向下一个节点的"指针"

     

    package com.ebiz.list.josepfu;
    
    /**
     * @author YHj
     * @create 2019-07-17 22:21
     * 表示节点的类
     */
    public 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;
        }
    
    
        @Override
        public String toString() {
            return "我是第" + no + "个Boy";
        }
    
    
    
    }

    2.定义单向链表类

       需要注意的是,josef问题是头尾相连的,在这也就是最后一个节点需要指向第一个节点,如果只有一个节点,那么该节点需要指向节点本身.

       解决josef问题,关键是理解最后的josef方法.

    package com.ebiz.list.josepfu;
    
    /**
     * @author YHj
     * @create 2019-07-17 22:16
     * 环形单项链表
     */
    public class SingleCircleList {
    
            //创建一个first 节点 没有编号也可以为空
            private  Boy firstBoy =new Boy(-1);
    
            //添加节点,构成环形链表   需要注意的是第一个节点需要指向节点本身
            public  void add(int num){
                    if (num < 1 ){
                        System.out.println("编号不正确");
                        return;
                    }
                    //创建辅助节点
                    Boy temp=null;
                    //添加节点
                    for (int i = 1; i <=num ; i++) {
                        Boy boy = new Boy(i);
                        if (i == 1){ //代表第一个节点
                            firstBoy=boy;
                            firstBoy.setNext(firstBoy);
                            temp=firstBoy;  //辅助接点
                        }else {
                            temp.setNext(boy);
                            boy.setNext(firstBoy);  //这里不能为temp 因为是环形链表,后面逐渐增加的节点的next应该是头节点
                            temp=boy;
                        }
                    }
            }
            //遍历环形链表
            public void list( ){
                if (firstBoy.getNo() == -1){
                    System.out.println("该环形链表为空!");
                    return;
                }
                //定义辅助指针
                Boy temp=firstBoy;
                while (true){
                    System.out.println(temp);
                    if (temp.getNext().getNo() == 1){
                        break;
                    }
                    temp=temp.getNext();
                }
            }
    
    
            /*
             josepfu问题的实现
             根据用户的输入,生成小孩出圈的顺序
             k:从哪里开始
             m:数几下
             num:玩游戏的小孩的数量
            */
            public void josepfu(int k,int m,int num){
                //数据校验
                if (k>num || k<1 || m<1 || num<1){
                    System.out.println("参数输入有误");
                }
                if(firstBoy.getNo() == -1){
                    System.out.println("链表节点为空!");
                }
                //创建辅助指针  帮助小孩完成出圈
                Boy temp=firstBoy;
                //循环遍历,将该辅助指针指向最后一个,即firstBoy前一个
                while (true){
                    if(temp.getNext() == firstBoy){
                        break;
                    }
                    temp=temp.getNext();
                }
                // 报数之前.让first 和temp移动到对应位置 在k处报数,让first和temp移动k-1,
                // 移动到开始报数的孩子身上
                for (int i = 1; i <=k-1 ; i++) {
                    firstBoy=firstBoy.getNext();
                    temp=temp.getNext();
                }
                while (true){
                    if (firstBoy == temp){
                        break;
                    }
                    //开始报数,第k个孩子,即firstBoy当前指向的孩子
                    //报m个数,,从第k个孩子本身报数,所以firstBoy移动m-1次,temp也移动m-1次
                    for (int i = 1; i <=m-1 ; i++) {
                        firstBoy=firstBoy.getNext();
                        temp=temp.getNext();
                    }
                    //上面循环结束时,firstBoy指向要出去的孩子
                    System.out.printf("小孩%d出圈",firstBoy.getNo());
                    //这是将firstBoy指向将要出去的孩子的下一位,并且temp的next指向他
                    firstBoy=firstBoy.getNext();
                    temp.setNext(firstBoy);
                }
                System.out.printf("最后留在圈中的小孩编号%d",firstBoy.getNo()); //或者temp
            }
    
    
    }

    3. 写一个简单测试类

    package com.ebiz.list.josepfu;
    
    /**
     * @author YHj
     * @create 2019-07-18 9:30
     */
    public class Test {
    
        public static void main(String[] args) {
    
            //创建环形链表
            SingleCircleList circleList = new SingleCircleList();
            //环形链表添加节点
            circleList.add(5);
            //遍历链表
            circleList.list();
    
            circleList.josepfu(1,2,5);
    
        }
    }

    有不懂的欢迎留言评论!

  • 相关阅读:
    过滤器,拦截器,监听器的区别
    Spring中的@Transactional(rollbackFor = Exception.class)属性详解
    java进阶知识--JAVA锁
    java进阶知识--23种设计模式
    java进阶知识--初识Jedis
    java进阶知识--初识redis
    java进阶知识--Nginx安装与部署
    java进阶知识--Nginx代理
    Linux常用命令
    Linux权限管理
  • 原文地址:https://www.cnblogs.com/jiushixihuandaqingtian/p/11224328.html
Copyright © 2020-2023  润新知