约瑟夫问题(有时也称为约瑟夫斯置换,是一个出现在计算机科学和数学中的问题。在计算机编程的算法中,类似问题又称为约瑟夫环。又称"丢手绢问题".)。
编号为1.2.3…….n的n个人按顺时针方向围坐一圈,开始任意选一个整数作为报数,从第一个人开始顺时针自1开始顺序报数,报到m时停止报数。报m的人出列,从出列的下一个人开始报数,报到m的人再退出,如此下去直到剩下一个人为止。
1.第一种单向的环形链表解决 首先将链表中的节点Boy创建出来/**
* 创建Boy节点
*
* @author Administrator
*/
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;
}
}
单向环形链表的添加方法
// 添加小孩 构成环形链表
public void addBoy(int nums) {
// 添加数目小于1时,不让游戏开始
if (nums < 1) {
System.out.println("nums的值不正确");
}
// 创建curBoy辅助变量 帮助构建环形
Boy curBoy = null;
// 使用for创建环形链表
// 循环创建boy 创建的是第一个就让头的下一个指向自己构成环形
for (int i = 1; i <= nums; i++) {
Boy boy = new Boy(i);
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());
if (curBoy.getNext() == first) {
// 说明链表遍历完了
System.out.println("遍历完毕");
break;
}
// curBoy后移
curBoy = curBoy.getNext();
}
}
然后创建单向链表的出圈方法
class CircleSingleLinkedList {
// 创建一个first节点 不赋值
private Boy first = null;
/**
* 出圈
* 根据用户的输入 表示小孩 一共几个 从哪个小孩数数,数几下
* @param nums
*/
public void countBoy(int nums, int firstNum, int count) {
//起始位置不能大于小孩个数 链表为空也不行 开始位置不能小于1
if (nums < firstNum || firstNum < 1) {
System.out.println("参数不合理");
return;
}
addBoy(nums);
//看创建的链表是否成功
if(first==null) {
System.out.println("链表为空");
}
// 创建辅助指针 并通过循环让他指向环形链表的最后一个节点
Boy helper = first;
while(true) {
if(helper.getNext()==first) {
break;
}
helper=helper.getNext();
}
// 报数时first要移动到开始报数时的位置
for (int i = 1; i < firstNum; i++) {
first=first.getNext();
helper=helper.getNext();
}
// 循环遍历
while (true) {
//假如辅助变量是first 说明只剩下一个节点
if (helper == first) {
System.out.println("说明圈中只有一个节点");
break;
}
//开始数数 for循环结束 first的位置就是要删除的节点的位置
for(int j = 1;j
2.第二种列表解决约瑟夫问题的思路
//big是一共有多少个孩子 order是从哪个孩子开始 nums是隔几个开始
public static void orderByInput(int big,int order,int nums){
//创建了一个数组
ArrayList list = new ArrayList<>();
//将每个学生加入到数组中
for(int i =1;i<=big;i++){
System.out.println("加入"+i+"个周硕");
list.add(i);
}
//当列表中的数只有一个的时候将他打印出来
while(true){
if(list.size()==1){
System.out.println("只剩下"+list.get(0)+"个周硕");
break;
}
//求出要取出的孩子 从哪个孩子开始加上隔的数 就是下一个要去除的孩子
//加上列表的元素数量是怕order+nums-1是负数 取模是为了数值超出列表长度
Integer kid = list.get((order+nums-1+list.size())%list.size());
//输出要移除的这个孩子的编号
System.out.println("移除"+kid.intValue()+"个周硕");
//移除这个孩子
list.remove(kid);
//让order后移
order = (order+1+list.size())%list.size();
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("游戏规则 一共n个小孩 从第m个小孩开始 每次数到 k 就移除这个人 最后只剩下一个人");
System.out.println("需要多少个人玩");
int i1 = scanner.nextInt();
System.out.println("第几个开始 最后剩下谁");
int i12 = scanner.nextInt();
System.out.println("最后剩下谁");
int i13 = scanner.nextInt();
orderByInput(i1,i12,i13);
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)