约瑟夫环 "密码问题"
问题描述:
编号为1、2、3、...、N的N个人按顺时针方向围坐一圈,每人持有一个密码 (正整 数)。从指定编号为1的人开始,按顺时针方向自1开始顺序报数,报到指定数M时停止报数,报M的人出列,并将他的密码作为新的M值,从他在顺时针方向的下一个人开始,重新从1报数,依此类推,直至所有的人全部出列为止。请设计一个程序求出出列的顺序,其中N≤30,M及密码值从键盘输入。
算法:
* 1、创建一个Person类[包含编号(id)、密码(password)]
* 2、创建一个链表(LinkedList类)接收Person类
* 3、创建一个数组列表(ArrayList)接收被淘汰的人的编号
* 4、使用循环,判断条件为链表的大小大于1
* 4-1、把指定password前的元素移除并添加到链表末尾
* 4-2、移除指定password的元素
* 4-3、把移除的元素赋给Person类的对象(用于获取编号和密码)
* 4-4、数组列表添加被移除元素的编号
* 4-5、把被移除元素的密码设置为新的指定的password
* 5、循环结束,链表只剩下最后一个元素(最后一个人)
package pack2;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Scanner;
public class Loop {
/**
* 算法:
* 1、创建一个Person类[包含编号(id)、密码(password)]
* 2、创建一个链表(LinkedList类)接收Person类
* 3、创建一个数组列表(ArrayList)接收被淘汰的人的编号
* 4、使用循环,判断条件为链表的大小大于1
* 4-1、把指定password前的元素移除并添加到链表末尾
* 4-2、移除指定password的元素
* 4-3、把移除的元素赋给Person类的对象(用于获取编号和密码)
* 4-4、数组列表添加被移除元素的编号
* 4-5、把被移除元素的密码设置为新的指定的password
* 5、循环结束,链表只剩下最后一个元素(最后一个人)
* */
public static void main(String[] args) {
try(Scanner input = new Scanner(System.in);){
char tag;
do {
System.out.print("输入要玩游戏的人数:");
int number = input.nextInt();
if(number > 0) {
int person = process(number);
if(person == -1)
System.out.println("存在无效的密码,正确的密码为除0以外的正整数。");
else
System.out.println("最后一个人为:"+person);
}else
System.out.println("人数应大于或等于0。");
System.out.println("\n=====================================");
System.out.print("是否继续(y/n):");
tag = input.next().charAt(0);
String temp = input.nextLine(); //吸收换行符,防止无法键入表达式
}while(tag=='Y' || tag=='y');
System.out.println("本次操作结束。");
}
}
//处理约瑟夫环方法
public static int process(int number) {
Scanner input = new Scanner(System.in);
LinkedList<Person> linkedList = new LinkedList<>(); //创建一个链表
ArrayList<Integer> arrayList = new ArrayList<>(); //创建一个数组列表
//依次输入密码
for (int i = 0; i < number; i++) {
System.out.print("输入第"+(i+1)+"个人的密码:");
int password = input.nextInt();
linkedList.addLast(new Person((i+1),password));
}
if(!isValid(linkedList))
return -1; //如果密码格式有误,返回-1
System.out.print("\n输入第一个随机密码(n>0):");
int password = input.nextInt();
if(password <= 0)
return -1;
while(linkedList.size() > 1) {
for (int i = 0; i < password-1; i++)
//把移除的password-1个元素添加到链表末尾
linkedList.addLast(linkedList.removeFirst());
Person person = linkedList.removeFirst(); //把指定password的元素移除并赋给person
arrayList.add(person.getId()); //数组列表添加person的编号
password = person.getPassword(); //设置新password为 person的password
}
System.out.println("淘汰顺序依次为:");
for (int i = 0; i < arrayList.size(); i++)
//如果i小于arrayList的大小减1,输出编号加“->”
if(i < arrayList.size()-1)
System.out.print(arrayList.get(i)+" -> ");
else //如果i为arrayList的大小减1,即最后一个元素,直接输出编号
System.out.println(arrayList.get(i));
return linkedList.removeFirst().getId(); //返回最后一个人的编号
}
public static boolean isValid(LinkedList<Person> linkedList) {
for (Person person : linkedList) {
if(person.getPassword() <= 0)
return false; //如果密码小于或等于0,返回false
}
return true;
}
//静态内部类(调用Person类的方法是静态的,所以Person类也应为静态的)
static class Person{
private int id; //编号
private int password; //密码
public Person(int id, int password) {
super();
this.id = id;
this.password = password;
}
public int getPassword() {
return password;
}
public int getId() {
return id;
}
}
}