约瑟夫(Josephu)问题
Josephu问题为: 设编号为1, 2,… n的n个人围坐一圈,约定编号为k (1<=k<=n) 的人从1开始报数,数到m的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
解决思路
用一个不带头结点的循环链表解决:先构成一个带有n个节点的单向环形链表,然后由k节点起从1开始计数,计到m时,对应节点从链表中删除,然后再从被删除节点的下一个节点开始数,直到最后一个节点从链表中删除。
代码实现
单向循环链表 和单链表区别在于单向循环链表的最后一个节点指向第一个节点,且没有头结点。
//约瑟夫问题单向环形链表解决
public class CircleSingleLinkedListDemo {
public static void main(String[] args) {
CircleSingleLinkedList list = new CircleSingleLinkedList();
list.addBoy(10);
list.traverseBoy();
list.countBoy(2,2,10);
}
}
class CircleSingleLinkedList{
public Boy first = null;//第一个节点
/**
* 添加num个节点
* @param num
*/
public void addBoy(int num){
if (num<1){
System.out.println("num的值不正确");
return;
}
Boy curBoy = null;//辅助变量,帮助遍历
for (int i = 1; i <=num ; i++) {
Boy boy= new Boy(i);//创建节点
if (i == 1){
//如果为第一个节点给第一个节点赋值
first=boy;
first.setNext(boy);
//cirBoy指向当前的first
curBoy = first;
}else {
//将当前节点指向下一个节点添加的节点boy
curBoy.setNext(boy);
//将最后一个节点指向第一个节点,形成环形链表
boy.setNext(first);
//curBoy后移一位
curBoy = boy;
}
}
}
/**
* 遍历环形链表
*/
public void traverseBoy(){
if (first==null){
System.out.println("环形链表为空");
return;
}
Boy curBoy = first;//辅助变量,用于遍历
System.out.print("遍历结果:");
while (true){
System.out.print(curBoy.getNo()+" ");
if (curBoy.getNext()==first){
break;
}
//当前节点curBoy后移一位
curBoy= curBoy.getNext();
}
System.out.println();
}
/**
*
* @param startNo 表示从第几个小孩开始数
* @param countNum 表示每次数几下
* @param nums 表示一共有几个小孩
*/
public void countBoy (int startNo,int countNum,int nums){
if (first ==null || startNo<1 ||countNum>nums){
System.out.println("参数输入有误");
return;
}
System.out.print("出圈顺序:");
//先让first节点和开始节点为同一个节点
for (int i = 0; i <startNo - 1 ; i++) {
first = first.getNext();
}
//创建辅助变量helper指向最后一个节点
Boy helper =first;
while (true){
if (helper.getNext()==first){
//遍历结束
break;
}
helper= helper.getNext();
}
//让firs和helper同时移动countNum -1次数后,first就为要出圈的那个节点
//循环操作,直到圈中只有一个节点
while (true) {
if (first == helper){
//圈中只有一个结点
break;
}
//firs和helper同时移动countNum -1次
for (int i = 0; i < countNum - 1; i++) {
first = first.getNext();
helper = helper.getNext();
}
//first就为要出圈的那个节点
System.out.print(first.getNo()+"-->");
//删除出圈的节点
first = first.getNext();
helper.setNext(first);
}
System.out.println(first.getNo());
}
}
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 +
'}';
}
}