环形链表
单向环形链表介绍
Josephu问题
Josephu 问题为:设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
n=5,即有5个人
k=1,从第一个·人开始报数
m=2,数2下
提示
用一个不带头结点的循环链表来处理Josephu 问题:先构成一个有n个结点的单循环链表,然后由k结点起从1开始计数,计到m时,对应结点从链表中删除,然后再从被删除结点的下一个结点又从1开始计数,直到最后一个结点从链表中删除算法结束。
约瑟夫问题创建环形链表图解
约瑟夫问题-小孩出窗思路分析
约瑟夫问题代码实现
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;
}
}
class CircleSinglyLinkedList{
private Boy first=null;
public void addNode(int num){
Boy curBoy=null;
for (int i=1;i<=num;i++){
Boy boy = new Boy(i);
if (i==1){
first=boy;
first.setNext(first);
curBoy=first;
}else {
curBoy.setNext(boy);
boy.setNext(first);
curBoy=boy;
}
}
}
//遍历环形链表
public void list(){
//数据校验
if (first==null){
System.out.println("链表为空");
}
Boy curboy=first;
while (true){
System.out.println(curboy.getNo());
if (curboy.getNext()==first){
break;
}
curboy=curboy.getNext();
}
}
//通过环形链表解决约瑟夫问题
/*
startno表示从第几个孩子开始数
countBoy表示数几下
num表示圈中有几个孩子
*/
public void countBoy(int startno,int countBoy,int num){
Boy helper=first;
//数据校验
if (first==null||startno<1||startno>num){
return;
}
//使辅助指针指向环形链表的最后一个节点
while (true){
if (helper.getNext()==first){
break;
}
helper=helper.getNext();
}
//找到开始报数的位子
for (int i=0;i<startno-1;i++){
first=first.getNext();
helper=helper.getNext();
}
while (true){
//只有一个节点
if (first==helper){
break;
}
//移动countBoy-1次
for (int i=0;i<countBoy-1;i++){
first=first.getNext();
helper=helper.getNext();
}
System.out.println("出队的节点使"+first.getNo());
first=first.getNext();
helper.setNext(first);
}
System.out.println("最后一个节点是"+first.getNo());
}
}
public class Josepfu {
public static void main(String[] args) {
CircleSinglyLinkedList csll = new CircleSinglyLinkedList();
csll.addNode(5);
csll.list();
csll.countBoy(1,2,5);
}
}