目录
前言
约瑟夫问题为:设编号为 1,2,… n 的 n 个人围坐一圈,约定编号为 k(1<=k<=n)的人从 1 开始报数,数到m 的那个人出列,它的下一位又从 1 开始报数,数到 m 的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
解决方法:依靠环形链表。
一、Josephu
情况一:假设总人数n=5,从编号为k=1开始报数,数到m=2时出列。
情况二:假设总人数n=25,从编号为k=10开始报数,数到m=5时出列。
情况三:假设总人数n=50,从编号为k=20开始报数,数到m=15时出列。
二、使用步骤
1.定义链表节点
class ListNode {
int val;
ListNode next;
public ListNode(int val) {
this.val = val;
}
}
2.创建环形列表方法
class CircleSingleLinkedList {
// 创建环形列表的方法
public ListNode createCircleList(int n) {// n为总人数
ListNode head = new ListNode(1);// 定义头结点,初始化为1
ListNode next = head;// 初始化next的位置
for (int i = 2; i <= n; i++) {
ListNode temp = new ListNode(i);
next.next = temp;
next = next.next;// 后移一位
}
next.next = head;// 头尾相连
return head;
}
// 出环形列表的方法
public void outList(ListNode list, int k, int m) {
ListNode head = list;
ListNode prehead = head;// 定义头结点的前一个节点
// 将prehead定位在链表最后一位
while (true) {
if (prehead.next == head) {
break;
}
prehead = prehead.next;
}
// 将head定位到编号k的位置上,perhead也移动同样步数,保证prehead.next==head
while ((k - 1) > 0) {
head = head.next;
prehead = prehead.next;
k--;
}
System.out.print("出圈编号:");
while (true) {
if (head == head.next) {// 如果头结点下一个为头结点,此时只剩头结点
break;
}
for (int i = 0; i < m - 1; i++) {// 移动m-1步,此时head指向的节点,是要出列的节点
head = head.next;
prehead = prehead.next;
}
// 输出编号
System.out.print(head.val + " ");
// 节点出列
head = head.next;
prehead.next = head;
}
// 输出最后一个编号
System.out.print(head.val + " ");
}
}
3.测试
public class Josepfu {
public static void main(String[] args) {
CircleSingleLinkedList test = new CircleSingleLinkedList();
//情况一
ListNode list = test.createCircleList(5);// 创建环形链表
test.outList(list, 1, 2);// 出列
System.out.println();
//情况二
ListNode list1 = test.createCircleList(25);// 创建环形链表
test.outList(list1, 10, 5);// 出列
System.out.println();
//情况三
ListNode list2 = test.createCircleList(50);// 创建环形链表
test.outList(list2, 20, 15);// 出列
}
}