题目:一群人围在一起丢手绢,开始指定从第m个人开始,然后瞬时针数k下,第k个人出列,剩下的人继续从0开始数到k,第k个人再次出列,问,最后一个人是谁?
文章思路来自b站 尚硅谷韩顺平老师的算法视频
package 算法.单向链表和双向链表的创建和遍历.约瑟夫问题之单向环形链表;
public class Josephu {
public static void main(String[] args) {
CircleLinkedList list =new CircleLinkedList();
list.addBoy(5);
list.show();
list.countBoy(1,2,5);
}
}
//创建一个单向环形链表
class CircleLinkedList{
//创建一个first结点,当前没有编号
private Boy first;
//num是创建的链表中结点的个数
public void addBoy(int nums){
if(nums<1){
return;
}
Boy curBoy =null;
for (int i = 1; i <=nums ; i++) {
//根据变量创建小孩结点
Boy boy = new Boy(i);
//如果是第一个小孩
if(i==1){
first=boy;
boy.setNext(first);//构成环
curBoy=first;//curBoy指向第一个小孩
}else {
curBoy.setNext(boy);
boy.setNext(first);
curBoy=boy;
}
}
}
public void show(){
if (first==null){
return;
}
Boy curBoy = first;
while (true){
System.out.println(curBoy);
if(curBoy.getNext()==first){
break;
}
curBoy=curBoy.getNext();
}
}
//根据用户输入,计算小孩出圈数据
//startNo 从第几个开始数 countNum数几下出队,小孩数量
public void countBoy(int startNo,int countNum,int num){
if(first==null||startNo>num||startNo<1) {
System.out.println("请重新输入");
return;
}
//创建辅助指针,并使其指向first的前一位
Boy helper =first;
while (helper.getNext()!=first){
helper=helper.getNext();
}
//从第startNo开始数,先把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==first){
//此时只有一个人
break;
}
for (int i = 0; i <countNum-1 ; i++) {
first=first.getNext();
helper=helper.getNext();
}
//输出当前结点,并将其出队
System.out.println(first);
first=first.getNext();
helper.setNext(first);
}
//退出循环后输出当前唯一的结点
System.out.println(first);
}
}
//创建一个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;
}
@Override
public String toString() {
return "Boy{" +
"no=" + no +
'}';
}
}