问题描述
- 有nums个人围成一圈、从n个人开始报数、数到m个人时出局。然后从m+1个人继续报数,依次如此…直到最后一个人出局,由此产生一个出队编号的序列。
代码实现
package com.hf.structures.linkedlist;
/**
* @Copyright (C), 2017-2019, Exela-hov
* @FileName: Joseph
* @Author: hf
* @Date: 2019/7/30 13:25
* @Description: 约瑟夫环【丢手帕问题】
*/
public class Joseph {
public static void main(String[] args) {
CircleSingleLinkedList list = new CircleSingleLinkedList();
//形成链表
list.add(39);
//遍历链表
list.show();
//约瑟夫出链表
list.countGirl(1,2,39);
}
}
//模拟环形链表
class CircleSingleLinkedList {
//确定环形链表头
private Girl first = null;
/**
* 功能描述:
* 〈
* 约瑟夫问题、出队编号序列产生
* 1.创建一个辅助指针(变量) temp,并指向链表的最后一个节点
* 2.将temp和first分别移动n-1个位置
* 3.循环报数时,让first 和 temp 指针同时 的移动 m - 1 次,移动完成即first就是要出圈的节点
* 4.使first节点的人出圈,first=first.next; , temp.next=first;
* 〉
*
* @className: CircleSingleLinkedList
* @author: hf
* @version: 1.0.0
* @date: 2019/7/30 13:58
* @param: [n 开始数的位置, m 数多少下, nums 总共有人围一圈]
* @return: void
*/
public void countGirl(int n, int m, int nums) {
if (first == null || n < 1 || m > nums) {
System.out.println("参数不符合规范....");
return;
}
//1
Girl temp = first;
while (temp.next != first) {
temp = temp.next;
}
//2
for (int i = 0; i < n - 1; i++) {
first = first.next;
temp = temp.next;
}
StringBuilder outLinkedList = new StringBuilder();
//3
while (temp != first) {
for (int i = 0; i < m - 1; i++) {
first = first.next;
temp = temp.next;
}
outLinkedList.append(first.num).append("->");
//4
first = first.next;
temp.next = first;
}
System.out.println("链表出圈序列:" + outLinkedList.append(first.num));
}
/**
* 功能描述:
* 〈
* 遍历环形链表
* 1.需使用first节点指向零时变量temp
* 2.使用while循环至temp.next=first;结束
* 〉
*
* @className: CircleSingleLinkedList
* @author: hf
* @version: 1.0.0
* @date: 2019/7/30 13:49
* @param: []
* @return: void
*/
public void show() {
if (first == null) {
return;
}
StringBuilder nums = new StringBuilder(" ");
Girl temp = first;
while (true) {
nums.append(temp.num).append(" ");
if (temp.next == first) {
break;
}
//temp后移
temp = temp.next;
}
System.out.println("环形链表数据:" + nums);
}
/**
* 功能描述:
* 〈
* 构建环形链表
* 1.创建一个节点、并指向first、形成环形
* 2.后没创建一个节点就将该节点加入环形队列即可,temp.next=节点N,节点N.next=first;
* 〉
*
* @className: CircleSingleLinkedList
* @author: hf
* @version: 1.0.0
* @date: 2019/7/30 13:31
* @param: [nums 链表中有几个节点]
* @return: void
*/
public void add(int nums) {
if (nums < 1) {
return;
}
Girl temp = null;
for (int i = 1; i <=nums; i++) {
Girl girl = new Girl(i);
if (i == 1) {
//构建单个节点的环形链表
first = girl;
first.next = first;
//指向临时变量
temp = first;
} else {
temp.next = girl;
girl.next = first;
//temp后移
temp = temp.next;
}
}
}
}
//创建节点
class Girl {
public int num;
public Girl next;
public Girl(int num) {
this.num = num;
}
}