• 链表--单向环形链表


    单向环形链表介绍

     单向环形链表应用场景

    Josephu(约瑟夫、约瑟夫环) 问题:

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

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

    约瑟夫问题-创建环形链表的思路图解:

    约瑟夫问题-小孩出圈的思路分析图:

    代码实现:

      1 package com.hut.linkedlist;
      2 
      3 public class Josepfu {
      4 
      5     public static void main(String[] args) {
      6         //测试环形链表的构成
      7             //创建环形单向链表对象
      8         CircleSingleLinkedList circle = new CircleSingleLinkedList();
      9         circle.addPerson(20);
     10         //显示环形单向链表
     11         circle.showPerson();
     12         
     13         //测试出圈
     14          System.out.println("=========================");
     15          circle.countPerson(3, 4, 20);
     16 
     17     }
     18 
     19 }
     20 
     21 //创建一个环形的单向链表
     22 class CircleSingleLinkedList{
     23     //创建一个first节点,当前没有编号
     24     private Person  first = null;
     25     
     26     //添加个人节点,构建一个环形的单向链表
     27     public void addPerson(int nums) {  //nums表示要添加的人数
     28         //校验nums
     29         if(nums <  1) {
     30             System.out.println("nums数值有误~~");
     31             return;
     32         }
     33         Person curPerson = null;  //辅助变量
     34         //使用for循环来构建单向环形链表
     35         for(int i =1;i <= nums;i ++) {
     36             //根据编号创建个人节点
     37             Person person = new Person(i);
     38             
     39             if(i == 1) {
     40                 first = person;
     41                 first.setNext(first); //指向first构成环形
     42                 curPerson = first;  //指向第一个人
     43             }else {
     44                 curPerson.setNext(person);
     45                 person.setNext(first);
     46                 curPerson = person;
     47             }
     48         }
     49     }
     50     
     51     //根据用户输入,计算个人出圈的顺序
     52     /**
     53      * startNum:表示开始报数的人的排序,就是K
     54      * countNum:表示数多少下,就是m
     55      * nums:表示总人数
     56      * */
     57     public void countPerson(int startNum,int countNum,int nums) {
     58         //先进行数据校验
     59         if(startNum < 1 || countNum < 1 || startNum > nums ) {
     60             System.out.println("输入数据有误,请重新输入~~");
     61             return;
     62         }
     63         //创建辅助变量,帮助个人出圈
     64         Person helper = first;
     65             //需求创建一个辅助指针(变量) helper , 事先应该指向环形链表的最后这个节点
     66         while(true) {
     67             if(helper.getNext() == first) { //{ // 说明 helper 指向最后一个人的那个节点
     68                 break;
     69             }
     70             helper = helper.getNext();
     71         }
     72         
     73         //在每个人报数前,先让 first 和 helper 移动 k - 1 次
     74         for(int i=0;i<startNum - 1;i++) {
     75             first = first.getNext();
     76             helper = helper.getNext();
     77         }
     78         ///当让人报数时,让 first 和 helper 指针同时 的移动 m - 1 次, 然后出圈
     79         //这里是一个循环操作,知道圈中只有一个节点
     80         while(true) {
     81             if(helper == first) { //说明圈中只有一个节点
     82                 break;
     83             }
     84             //让 first 和 helper 指针同时 的移动 countNum - 1
     85             for(int j=0;j<countNum - 1;j++) {
     86                 first = first.getNext();
     87                 helper = helper.getNext();
     88             }
     89             //这是first指向的节点就是出圈的节点
     90             System.out.printf("个人%d 出圈
    ", first.getNo());
     91             //这时将first指向的小孩出圈
     92             first = first.getNext();
     93             helper.setNext(first);;
     94         }
     95         System.out.printf("最后留在圈中的个人编号%d 
    ", first.getNo());
     96         
     97     }
     98     
     99     //遍历当前环形单向链表
    100     public void showPerson() {
    101         //判断链表是否为空
    102         if(first == null) {
    103             System.out.println("没有任何人~~");
    104             return;
    105         }
    106         //因为first不能动,所以创建一个辅助变量curPerson来帮忙遍历
    107         Person curPerson = first;
    108         while(true) {
    109             System.out.printf("个人的编号为: %d
    ",curPerson.getNo());
    110             if(curPerson.getNext() == first) {
    111                 break;
    112             }
    113             curPerson = curPerson.getNext(); //curPerson后移
    114         }
    115     }
    116     
    117     
    118 }
    119 
    120 //创建一个Person类表示节点
    121 class Person{
    122     private int no; //编号
    123     private Person next; //指向下一个节点,默认null
    124     
    125     public Person(int no) {
    126         this.no = no;
    127     }
    128 
    129     public int getNo() {
    130         return no;
    131     }
    132 
    133     public void setNo(int no) {
    134         this.no = no;
    135     }
    136 
    137     public Person getNext() {
    138         return next;
    139     }
    140 
    141     public void setNext(Person next) {
    142         this.next = next;
    143     }
    144     
    145     
    146 }
  • 相关阅读:
    树上后缀排序
    省选模拟赛day4
    吉司机线段树
    虚树复习
    bzoj 3065: 带插入区间K小值
    luogu P2462 [SDOI2007]游戏
    luogu P3783 [SDOI2017]天才黑客
    企业为取得交易性金融资产发生的交易费用应记入到投资收益科目
    旧手机数据迁移到新手机
    应收票据业务操作(背书、背书退回、退票)
  • 原文地址:https://www.cnblogs.com/cleanlife/p/14375356.html
Copyright © 2020-2023  润新知