zoukankan      html  css  js  c++  java
  • 约瑟夫问题以及环形链表的解决方案

    约瑟夫问题介绍:  

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

     提示

    用一个不带头结点的循环链表来处理Josephu问题:先构成一个有n个结点的单循环链表
    
    然后由k结点起从1开始计数,计到m时,对应结点从链表中删除。
    
    然后再从被删除结点
    
    的下一个结点又从1开始计数,直到最后一个结点从链表中删除算法结束。 

     思路:

    构建一个单向的环形链表思路:
    
    1.先创建第一个节点让first指向该节点,并形成环形
    
    2.后面当我们每创建一个新的节点, 就把该节点,加入到已有的环形链表中即可.
    
    遍历环形列表:
    
    1.先让一个辅助指针(变量curBoy,指向first节点)
    2.然后通过一个while循环遍历 该环形链表即可curBoy.next == first结束

     

     添加小朋友代码实现:

    /**
         * 添加小孩的节点
         * nums:参与游戏的小孩个数
         */
        public void addBoy(int nums){
            if (nums < 1){
                System.out.println("您输入的数据有误!");
                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;//让辅助指针指向第一个节点
                }else{
                    curBoy.setNext(boy);//从第二个小朋友开始,让辅助指针的下一个节点 指向 新的节点
                    boy.setNext(first);//再让第二个小朋友的下一个节点 指向 第一个小朋友
                    curBoy = boy;//让curBoy指向boy,也就是辅助节点向后移
                }
            }
        }
    View Code

     遍历链表代码实现:

    /**
         * 遍历环形链表
         */
        public void Traverse(){
            //判断链表是否为空
            if (first == null){
                System.out.println("链表为空!");
                return;
            }
            //因为first不能动,所以在这定义辅助指针
            Boy curBoy = first;
    
            while (true){
                System.out.println("小朋友的编号为:"+curBoy.getNo());
                if (curBoy.getNext() == first)//说明已经遍历完毕
                    break;
                curBoy = curBoy.getNext();//让curBoy后移
            }
        }
    View Code

     小朋友出圈顺序分析:

     

      小朋友出圈代码实现:

    /**
         * 根据用户的输入,计算出小朋友出圈的顺序
         * @param startNo :表示从哪个小朋友开始报数
         * @param countNum:表示数几下
         * @param nums:表示最初有多少小朋友参与游戏
         */
        public void countBoy(int startNo,int countNum,int nums){
            if (first == null || startNo < 0 || startNo > nums){
                System.out.println("参数输入有误!");
                return;
            }
            //创建辅助节点,帮助小朋友出圈
            Boy temp = first;
            while (true){
                if (temp.getNext() == first)//辅助指针temp事先应该指向节点的最后一个位置
                    break;
                temp = temp.getNext();//向后移动,找到最后链表的最后一个位置
            }
            //移动小朋友到指定位置上面
            for (int j = 0;j<startNo-1;j++){
                first = first.getNext();
                temp = temp.getNext();
            }
            //小朋友报数,让first跟temp指针同时移动countNum-1次
            while (true){
                if (first == temp) break;//说明圈中就只有一个小朋友了,就结束
    
                for (int i=0;i<countNum-1;i++){
                    first = first.getNext();
                    temp = temp.getNext();
                }
                System.out.println("小朋友的编号是:"+first.getNo());
                first = first.getNext();//让first指针后移
                temp.setNext(first);//让辅助指针temp指向first。这样小朋友就出圈了
            }
            System.out.println("最后留在圈中的小朋友编号是:"+first.getNo());
        }
    View Code

    完整代码:

    package Demo04_环形链表与约瑟夫问题;
    
    /**
     * 约瑟夫问题介绍:
             Josephu问题为:设编号为1, 2, .n的n个人围坐一圈,约定编号为k (1<=k<=n) 的人从1开始报数,数到m的那个人出列,它
             的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
             n=5,即有s个人
             k=1,从第一个人开始报数
             m=2,数2下
    
     * ➢提示
             用一个不带头结点的循环链表来处理Josephu问题:先构成一个有n个结点的单循环链表,
             然后由k结点起从1开始计数,计到m时,对应结点从链表中删除,然后再从被删除结点
             的下一个结点又从1开始计数,直到最后一个结点从链表中删除算法结束。
     思路:
         构建一个单向的环形链表思路
             1.先创建第一个节点让first指向该节点,并形成环形
             2.后面当我们每创建一个新的节点, 就把该节点,加入到已有的环形链表中即可.
         遍历环形链表
             1.先让一个辅助指针(变量curBoy,指向first节点)
             2.然后通过一个while循环遍历 该环形链表即可curBoy.next == first结束
    
     */
    
    public class Test01_约瑟夫问题 {
        public static void main(String[] args) {
            CircularLinkedList list = new CircularLinkedList();
            list.addBoy(5);//加入五个小朋友
    
            list.countBoy(1,2,5);
        }
    }
    /**
     * 创建单向环形链表类
     */
    class CircularLinkedList{
        //创建first节点
        private Boy first = null;
    
        /**
         * 添加小孩的节点
         * nums:参与游戏的小孩个数
         */
        public void addBoy(int nums){
            if (nums < 1){
                System.out.println("您输入的数据有误!");
                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;//让辅助指针指向第一个节点
                }else{
                    curBoy.setNext(boy);//从第二个小朋友开始,让辅助指针的下一个节点 指向 新的节点
                    boy.setNext(first);//再让第二个小朋友的下一个节点 指向 第一个小朋友
                    curBoy = boy;//让curBoy指向boy,也就是辅助节点向后移
                }
            }
        }
        /**
         * 遍历环形链表
         */
        public void Traverse(){
            //判断链表是否为空
            if (first == null){
                System.out.println("链表为空!");
                return;
            }
            //因为first不能动,所以在这定义辅助指针
            Boy curBoy = first;
    
            while (true){
                System.out.println("小朋友的编号为:"+curBoy.getNo());
                if (curBoy.getNext() == first)//说明已经遍历完毕
                    break;
                curBoy = curBoy.getNext();//让curBoy后移
            }
        }
    
        /**
         * 根据用户的输入,计算出小朋友出圈的顺序
         * @param startNo :表示从哪个小朋友开始报数
         * @param countNum:表示数几下
         * @param nums:表示最初有多少小朋友参与游戏
         */
        public void countBoy(int startNo,int countNum,int nums){
            if (first == null || startNo < 0 || startNo > nums){
                System.out.println("参数输入有误!");
                return;
            }
            //创建辅助节点,帮助小朋友出圈
            Boy temp = first;
            while (true){
                if (temp.getNext() == first)//辅助指针temp事先应该指向节点的最后一个位置
                    break;
                temp = temp.getNext();//向后移动,找到最后链表的最后一个位置
            }
            //移动小朋友到指定位置上面
            for (int j = 0;j<startNo-1;j++){
                first = first.getNext();
                temp = temp.getNext();
            }
            //小朋友报数,让first跟temp指针同时移动countNum-1次
            while (true){
                if (first == temp) break;//说明圈中就只有一个小朋友了,就结束
    
                for (int i=0;i<countNum-1;i++){
                    first = first.getNext();
                    temp = temp.getNext();
                }
                System.out.println("小朋友的编号是:"+first.getNo());
                first = first.getNext();//让first指针后移
                temp.setNext(first);//让辅助指针temp指向first。这样小朋友就出圈了
            }
            System.out.println("最后留在圈中的小朋友编号是:"+first.getNo());
        }
    }
    
    /**
     * 创建小孩类,每个小孩表示一个节点
     */
    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;
        }
    }
    View Code
  • 相关阅读:
    1058 A+B in Hogwarts (20)
    1036. Boys vs Girls (25)
    1035 Password (20)
    1027 Colors in Mars (20)
    1009. Product of Polynomials (25)
    1006. Sign In and Sign Out
    1005 Spell It Right (20)
    1046 Shortest Distance (20)
    ViewPager页面滑动,滑动到最后一页,再往后滑动则执行一个事件
    IIS7.0上传文件限制的解决方法
  • 原文地址:https://www.cnblogs.com/zhangzhixi/p/13522745.html
Copyright © 2011-2022 走看看