约瑟夫问题
有n个人,编号为1~n,从第k(1<=k<=n)个人开始报数,从1开始报,报到m的人会出列,然后从第m+1个人开始,重复以上过程。直到所有让出列,由此产生一个出队序列
分析
构建一个单向单环形链表思路
1、先创建第一个节点,让first指向该节点,并形成环形
2、后面当我们每创建一个新当节点,就把该节点加入到已有到环形链表中
遍历环形链表思路
1、先生存一个辅助变量cur,然后指向first
2、通过while遍历,cur.next == first 结束
实现思路
输入参数n k m
1、创建一个辅助变量helper,事先指向最后一个节点
2、找到报数的目标,first和helper移动k-1次
3、当报数时候,让first和helper同时移动m-1次
4、这时候将first指向节点出圈,经过(first = first.next,Helper.next = first;),原来节点就消失了
package linkedlist;
public class Josepfu {
public static void main(String[] args) {
CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
circleSingleLinkedList.count(1,2,5);
}
}
// 创建一个环形的单向链表
class CircleSingleLinkedList{
// 创建一个first节点
public JNode first = new JNode(-1);
// 添加节点,构成一个环形链表
public void add(int nums){
if (nums < 1){
System.out.println("添加不合理");
return;
}
// 辅助变量
JNode cur = null;
for (int i = 1; i <= nums; i++){
// 根据编号创建节点
JNode jNode = new JNode(i);
if(i == 1){
first = jNode;
first.next = first;
cur = first;
} else {
cur.next = jNode;
jNode.next = first;
cur = jNode;
}
}
}
// 遍历当前环形链表
public void list(){
if(first == null){
System.out.println("空");
return;
}
JNode cur = first;
while (true){
System.out.println(cur.id);
if (cur.next == first){
break;
}
cur = cur.next;
}
}
/**
*
* @param no 第几个节点开始
* @param countNum 数多少下
* @param nums 初始有多少个节点
*/
public void count(int no,int countNum,int nums){
// 校验
if (first == null || no < 1 || no > nums){
System.out.println("参数有误");
return;
}
this.add(nums);
// 创建辅助变量
JNode helper = first;
// 将辅助变量指向最后一个节点
while (true){
if (helper.next == first){
break;
}
helper = helper.next;
}
// 找到开始的节点
for (int j = 0; j < no-1; j++){
first = first.next;
helper = helper.next;
}
// 报数前,让first和helper同时移动 m-1 次,然后出圈
while (true){
if(helper == first){
break;
}
for (int j = 0; j < countNum-1; j++){
first = first.next;
helper = helper.next;
}
// 出圈节点
System.out.println(first.id);
// 出圈
first = first.next;
helper.next = first;
}
System.out.println(helper.id);
}
}
// 创建节点
class JNode {
public int id;
public JNode next;
public JNode(int id){
this.id = id;
}
}