跟着视频走了一遍,通过环形链表解决约瑟夫问题的,方式和之前的单链表大同小异,没有太值得说的地方,主要还是作为一个学习道路上的记录。
注意一下,当没有任何对象引用时,就会被垃圾回收器回收这一特点,以及环形链表一个节点时,是自己指向自己,问题能得到很好的解决。
其实这个的主要收获还是,通过跑一遍这个流程,
1、加强认识了定义私有类型“private”后,对其的一些比较便捷操作;
2、学习了方法头注释模板的使用
package com.chen;
import com.sun.prism.shader.Solid_TextureFirstPassLCD_AlphaTest_Loader;
/**
* @author 淡
* @create 2020-02-11 14:27
*/
public class CircleSingleLinkedListDemo {
public static void main(String[] args) {
CircleSinglelinkedList circleSingleLinkedList = new CircleSinglelinkedList();
circleSingleLinkedList.addBoy(5);
circleSingleLinkedList.showBoy();
circleSingleLinkedList.countBoy(1, 2,5);
}
}
class CircleSinglelinkedList{
//创建一个 first 节点 当前没有编号,置为 null
private Boy first = null;
//添加小孩节点,构建环形链表
public void addBoy(int nums){
//数据校验,防止 nums 范围不合规
if(nums < 1){
System.out.println("nums数据不正确");
return;
}
//辅助指针,帮助构建环形链表
Boy curBoy = null;
for (int i = 1; i <= nums; i++) {
//根据编号创建小孩节点
Boy boy = new Boy(i);
//如果是第一个小孩,Boy.setNext应该指向自身
//辅助指针curBoy:应该指向新建的 boy处
//链表的末尾节点(curBoy.setNext):指向新建的 boy处
//新建 boy的 .srtNext:应指向 first处,以构建完整的环
if(i == 1){
first = boy;
first.setNext(first);
curBoy = first;
} else{
curBoy.setNext(boy);
boy.setNext(first);
curBoy = boy;
}
}
}
//遍历当前环形链表
public void showBoy(){
//判断链表是否为空
if(first == null){
System.out.println("没有小孩。。。");
return;
}
//辅助指针curBoy:帮助完成遍历
Boy curBoy = first;
while(true){
System.out.println("小孩的编号:" + curBoy.getNo() );
//已经遍历完成,当前 curBoy为最后一个节点
if(curBoy.getNext() == first)
break;
//后移一位,进入下一节点
curBoy = curBoy.getNext();
}
}
/**
* 根据用户的输入,计算出小孩出圈的顺序
* <br/>
* @param startNo 表示从第几个小孩开始数数
* @param countNum 表示数几下
* @param nums 表示最初有几个小孩在圈内
* @return void
* @author 淡
* @date 2020/2/11 16:13
*/
public void countBoy(int startNo, int countNum, int nums){
// 校验数据
if(first == null || startNo < 1 || startNo > nums){
System.out.println("参数输入有误请重新输入");
return;
}
//辅助指针(helper):帮助完成小孩出圈,事先指向环形链表最后的节点
Boy helper = first;
while(true){
if(helper.getNext() == first)
break;
helper = helper.getNext();
}
//小孩报数前,first 和 helper 应该移动到指定的位置,即:startNo-1
//表示从第几个小孩开始数
for (int i = 0; i < startNo - 1; i++) {
first = first.getNext();
helper = helper.getNext();
}
//小孩开始报数,让 first 和 helper 同时移动 countNum-1 次,然后出圈
while(true){
if(helper.getNext() == helper)
break;
for (int i = 0; i < countNum - 1; i++) {
first = first.getNext();
helper = helper.getNext();
}
//此时,first 和 helper 都指向要出圈的小孩节点
System.out.printf("小孩 %d 出圈\n", first.getNo());
//使两者指向的出圈小孩节点 “出圈”
//出圈的小孩节点:本来有 first.getNext() 和 helper.setNext() 指向
// 但是现在没有了,失去了所有指向,成为了“垃圾”,垃圾处理器自动回收
first = first.getNext();
helper.setNext(first);
}
System.out.println("最后在圈中的小孩:" + first.getNo());
}
}
//创建一个 Boy 类,表示一个节点
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;
}
}