链表--单向环形链表

单向环形链表介绍

 单向环形链表应用场景

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 }
原文地址:https://www.cnblogs.com/cleanlife/p/14375356.html