zoukankan      html  css  js  c++  java
  • 单向环形链表 约瑟夫问题

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

    链表如下图

    数2下 自己也要数 所以只会移动1次 

    构建链表,遍历链表 分析图

     first.next = 2

    3.next = first 让最后一个元素的next指向first

     首先

    创建一个环形链表

    // 创建一个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
                            //不太理解 这里设置和取 为什么要用set get
                            first.setNext(first); // 构成环   自己指向自己
                            curBoy = first; // 让curBoy指向第一个小孩 因为first不能动 所以要这个辅助指针
                    } else {
                            //代表不是第一个节点
                            curBoy.setNext(boy);// 前一个的指向后一个
                            boy.setNext(first);// 后一个(最后一个)指向最前面的
                            curBoy = boy; //把curBoy的指针后移  
                    }
            }
    }


    遍历这个链表

    // 遍历当前的环形链表
    public void showBoy() {
            // 判断链表是否为空
            if (first == null) {
                    System.out.println("没有任何小孩~~");
                    return;
            }
            // 因为first不能动,因此我们仍然使用一个辅助指针完成遍历
            Boy curBoy = first;
            while (true) {
                    System.out.printf("小孩的编号 %d 
    ", 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 < 1 || startNo > nums) {
                    System.out.println("参数输入有误, 请重新输入");
                    return;
            }
            // 创建要给辅助指针,帮助完成小孩出圈
            Boy helper = first;
            // 需求创建一个辅助指针(变量) helper , 事先应该指向环形链表的最后这个节点
            while (true) {
                    if (helper.getNext() == first) { // 说明helper指向最后小孩节点
                            break;
                    }
                    helper = helper.getNext();//helper要在first后面一个 一直遍历到最后一个
            }
            //小孩报数前,先让 first 和  helper 移动 k - 1次   为什么是k-1  比如从2开始 但是实际只移动了一次 首先会在1的位置  但是不需要移动 只要让first指向就可以了 然后再移动一下 就移动到2了 所以移动次数是k-1次
            for(int j = 0; j < startNo - 1; j++) {
                    first = first.getNext();
                    helper = helper.getNext();
            }
            //当小孩报数时,让first 和 helper 指针同时 的移动  m  - 1 次, 然后出圈  m-1因为数到m 自己也会数一下
            //这里是一个循环操作,直到圈中只有一个节点
            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出圈
    ", first.getNo());
                    //这时将first指向的小孩节点出圈
                    first = first.getNext();
                    helper.setNext(first); //
                    
            }
            System.out.printf("最后留在圈中的小孩编号%d 
    ", first.getNo());
            
    }

    全部代码

    package com.atguigu.linkedlist;
    
    public class Josepfu {
    
            public static void main(String[] args) {
                    // 测试一把看看构建环形链表,和遍历是否ok
                    CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
                    circleSingleLinkedList.addBoy(125);// 加入5个小孩节点
                    circleSingleLinkedList.showBoy();
                    
                    //测试一把小孩出圈是否正确
                    circleSingleLinkedList.countBoy(10, 20, 125); // 2->4->1->5->3
                    //String str = "7*2*2-5+1-5+3-3";
            }
    
    }
    
    // 创建一个环形的单向链表
    class CircleSingleLinkedList {
            // 创建一个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; // 让curBoy指向第一个小孩
                            } else {
                                    curBoy.setNext(boy);//
                                    boy.setNext(first);//
                                    curBoy = boy;//这里相当于在进行next操作 使其往后移
                            }
                    }
            }
    
            // 遍历当前的环形链表
            public void showBoy() {
                    // 判断链表是否为空
                    if (first == null) {
                            System.out.println("没有任何小孩~~");
                            return;
                    }
                    // 因为first不能动,因此我们仍然使用一个辅助指针完成遍历
                    Boy curBoy = first;
                    while (true) {
                            System.out.printf("小孩的编号 %d 
    ", 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 < 1 || startNo > nums) {
                            System.out.println("参数输入有误, 请重新输入");
                            return;
                    }
                    // 创建要给辅助指针,帮助完成小孩出圈
                    Boy helper = first;
                    // 需求创建一个辅助指针(变量) helper , 事先应该指向环形链表的最后这个节点
                    while (true) {
                            if (helper.getNext() == first) { // 说明helper指向最后小孩节点
                                    break;
                            }
                            helper = helper.getNext();
                    }
                    //小孩报数前,先让 first 和  helper 移动 k - 1次
                    for(int j = 0; j < startNo - 1; j++) {
                            first = first.getNext();
                            helper = helper.getNext();
                    }
                    //当小孩报数时,让first 和 helper 指针同时 的移动  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出圈
    ", first.getNo());
                            //这时将first指向的小孩节点出圈
                            first = first.getNext();
                            helper.setNext(first); //
                            
                    }
                    System.out.printf("最后留在圈中的小孩编号%d 
    ", first.getNo());
                    
            }
    }
    
    // 创建一个Boy类,表示一个节点
    class Boy {
            private int no;// 编号
            private Boy next; // 指向下一个节点,默认null
    
            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;
            }
    
    }
  • 相关阅读:
    从Oracle提供两种cube产品说开
    Sql Server DWBI的几个学习资料
    Unload Oracle data into text file
    初学Java的几个tips
    我常用的Oracle知识点汇总
    benefits by using svn
    如何在windows上使用putty来显示远端linux的桌面
    building commercial website using Microsoft tech stack
    Understand Thread and Lock
    Update google calendar by sunbird
  • 原文地址:https://www.cnblogs.com/cnng/p/12329618.html
Copyright © 2011-2022 走看看