约瑟夫问题的描述
丢手绢,sum个小朋友做成一圈,第一次从第k个人开始数,每次数m个则数到的人出列,直到只剩下1个人。输出出圈的顺序。
约瑟夫问题的抽象
节点的信息
class Boy {
public int no;
public Boy next;
public Boy(int no) {
this.no = no;
}
@Override
public String toString() {
return "Boy{" +
"no=" + no +
'}';
}
1环形单向链表的创建思路
代码实现
public Boy circle(int sum) {
if (sum <= 1) {
System.out.println("请输入至少两个节点");
return null;
}
Boy temp = head;
for (int i = 1; i <= sum; i++) {
Boy boy = new Boy(i);
temp.next = boy;
boy.next = head.next;
temp = temp.next;
}
return head;
}
2环节点的遍历
代码实现
public void displayCircle( Boy head){
if(head.next==null){
System.out.println("链表为空");
return;
}
Boy temp=head.next;
while(temp.next!=head.next){
System.out.println(temp.no);
temp=temp.next;
}
System.out.println(temp.no);
}
约瑟夫问题的实现
约瑟夫问题的抽象
几点说明:
- 首先最一开始helper指针是指向第一个节点的前一个节点,也就是最后一个节点,temp节点指向第一个节点。
- 以上图为例,当从1号开始后,每数三个数,删除一个节点,此时需要将temp和helper指针移动到相应的节点上(要移动两次,因为第一个节点要数一个),然后删除操作是:先让temp向下移动一个节点temp=temp.next,然后让helper指针指向新的temp即:helper.next=temp
- 注意:此图解中是从第一个节点开始数,但是当知道该从第k个小孩开始数之后,要移动两个指针,使temp节点移动到要删除的节点,此时需要有一个for循环,来指定两个指针移动的节点数目k-1!
代码实现
public void out(int sum, int k, int m) {
if (head.next == null || sum <= 1 || k > sum) {
System.out.println("你输入的参数有误");
return;
}
Boy helper = head.next;
Boy temp = head.next;
while (true) {
if (helper.next == temp) {
break;
}
helper = helper.next;
}
for (int j = 0; j < k - 1; j++) {
temp = temp.next;
helper = helper.next;
}
while (true) {
if (helper == temp) {
break;
}
for (int j = 0; j < m - 1; j++) {
temp = temp.next;
helper = helper.next;
}
System.out.println("节点【" + temp.no + "】出圈");
temp = temp.next;
helper.next = temp;
}
System.out.println("最后留的节点是" + helper.next);
}
测试代码:
package com.njupt.suanfa;
public class Josephu {
public static void main(String[] args) {
Circle circle = new Circle();
Boy boy0 = circle.circle(4);
circle.displayCircle(boy0);
circle.out(4, 1, 3);
}
}
class Circle {
Boy head = new Boy(0);
public Boy circle(int sum) {
if (sum <= 1) {
System.out.println("请输入至少两个节点");
return null;
}
Boy temp = head;
for (int i = 1; i <= sum; i++) {
Boy boy = new Boy(i);
temp.next = boy;
boy.next = head.next;
temp = temp.next;
}
return head;
}
public void displayCircle(Boy head) {
if (head.next == null) {
System.out.println("链表为空");
return;
}
Boy temp = head.next;
while (temp.next != head.next) {
System.out.println(temp.no);
temp = temp.next;
}
System.out.println(temp.no);
}
public void out(int sum, int k, int m) {
if (head.next == null || sum <= 1 || k > sum) {
System.out.println("你输入的参数有误");
return;
}
Boy helper = head.next;
Boy temp = head.next;
while (true) {
if (helper.next == temp) {
break;
}
helper = helper.next;
}
for (int j = 0; j < k - 1; j++) {
temp = temp.next;
helper = helper.next;
}
while (true) {
if (helper == temp) {
break;
}
for (int j = 0; j < m - 1; j++) {
temp = temp.next;
helper = helper.next;
}
System.out.println("节点【" + temp.no + "】出圈");
temp = temp.next;
helper.next = temp;
}
System.out.println("最后留的节点是" + helper.next);
}
}
class Boy {
public int no;
public Boy next;
public Boy(int no) {
this.no = no;
}
@Override
public String toString() {
return "Boy{" +
"no=" + no +
'}';
}
}
结果:
1
2
3
4
节点【3】出圈
节点【2】出圈
节点【4】出圈
最后留的节点是Boy{no=1}
如果感兴趣的话,可以多输入几组数哦!!!
|