约瑟夫问题:设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
nums = 10 , 即有10个人
start = 2, 从第二个人开始报数
count = 3, 数3下
具体实现如下:
1、创建一个小孩节点对象
class Child{
private int no;
private Child next;
public Child(int no){
this.no = no;
}
public void setNo(int no) {
this.no = no;
}
public int getNo() {
return no;
}
public void setNext(Child next) {
this.next = next;
}
public Child getNext() {
return next;
}
}
2、构建一个单向环形链表
1)先创建第一个节点, 让 first 指向该节点
2)异常判断:判断传的小孩个数是否大于1
3)创建当前节点cur,并使用for循环依次创建链表的各个节点。并把该节点,加入到已有的环形链表中即可.
当i=1时,first指向对应编号为1的节点。并设置first的下个节点为自己(形成环形链表),设置当前节点cur指向first。
当i!=1时,直接在已有节点后追加对应i的节点,设置当前节点cur的下个节点指向对应i的节点。设置对应i的节点的下个节点为first(形成环形链表).最后再设置当前节点cur为对应i的节点。
class CircleSingleLinedList{
Child first = new Child(-1);
//添加小孩节点,形成环形链表
public void addChild(int nums){
if(nums<1){
System.out.println("小孩个数不正确,请重新输入");
return;
}
Child curChild = null;
for(int i=1;i<=nums;i++){
Child child = new Child(i);
if(i==1){
first = child;
first.setNext(first);
curChild = first;
}else {
curChild.setNext(child);
child.setNext(first);
curChild = child;
}
}
}
}
3、遍历环形链表
1)先判断链表是否为空,如果为空则为空链表,直接return。
2) 然后创建一个辅助指针(变量) curChild,指向first节点。
3)最后通过一个while循环遍历 该环形链表。当curChild.next == first 时退出循环。
//遍历链表
public void showChild(){
if(first == null){
System.out.println("没有小孩~~~~~~");
return;
}
Child curChild = first;
while (true){
System.out.printf("小孩的编号 %d\n",curChild.getNo());
if(curChild.getNext() == first){
break;
}
curChild = curChild.getNext();
}
}
4、约瑟夫问题实现
1)异常情况处理
头结点为空时return
开始节点Start不在1到链表长度之间时return
每次数几个数(步长)<1时return
2)创建头节点head、尾节点对象last。分别指向first
3) 使用while循环,当last的下个节点为head时退出循环,并为last节点赋值。
4)for循环让头结点head,last尾结点移动start-1次
5)while循环,链表长度不等于0时,使用for循环移动头结点head,尾结点last ,步长size-1次
6) 第5步,得到出圈小孩编号。接着删除头结点,步骤如下:
先保存头结点的下一个结点到nextnode
然后将尾结点的下一个结点指向nextnode
然后设置头结点的下一个结点为空
接着更新链表的长度
最后设置头结点指向nextnode
//根据用户的输入,计算出小孩出圈的顺序
public void countChild(int start,int size,int nums) {
Child head = first;
Child last = first;
if (head == null) {
return;
}
if (start < 1 || start > nums||size < 1) {
System.out.println("请输入正确的参数~~");
return;
}
while (true){
if(last.getNext() == head){
break;
}
last = last.getNext();
}
for (int i = 0; i < start - 1; i++) {
head = head.getNext();
last = last.getNext();
}
while (nums != 0) {
for (int i = 0; i < size - 1; i++) {
head = head.getNext();
last = last.getNext();
}
System.out.printf("编号为%d的小孩出圈\n", head.getNo());
Child nextChild = head.getNext();
last.setNext(nextChild);
head.setNext(null);
nums--;
head = nextChild;
}
System.out.printf("最后留在圈中的小孩是%d",head.getNo());
}
5、测试类
public class Josephu {
public static void main(String[] args) {
CircleSingleLinedList childLinklist = new CircleSingleLinedList();
childLinklist.addChild(10);
// childLinklist.showChild();
childLinklist.countChild(2,3,10);//出圈的顺序4->7->10->3->8->2->9->6->1->5
}
}
输出结果:
编号为4的小孩出圈
编号为7的小孩出圈
编号为10的小孩出圈
编号为3的小孩出圈
编号为8的小孩出圈
编号为2的小孩出圈
编号为9的小孩出圈
编号为6的小孩出圈
编号为1的小孩出圈
编号为5的小孩出圈
最后留在圈中的小孩是5