约瑟夫问题:
N个人围成一圈,从约定编号为K的人开始报数,第M个将出圈,依次类推,直到最后剩下最后一个人。
class person {
private int no;//编号
private person next;//下一位
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public person getNext() {
return next;
}
public void setNext(person next) {
this.next = next;
}
public person(int no) {
this.no = no;
}
}
public class Josephus {
person first = null;
public void addperson(int num) {//往环里面添加成员
person point = null;
for (int i = 1; i <= num; i++) {
person p = new person(i);
if (i == 1) {//指向自己
first = p;
first.setNext(first);
point = first;
} else {//下一位成员加入环
p.setNext(first);
point.setNext(p);
point = p;
}
}
}
public void showPerson() {//展示环中已有成员
if (first == null) {
System.out.println("链表为空!");
return;
}
person point = first;
while (true) {
System.out.println("成员编号:" + point.getNo());
if (point.getNext() == first) {
break;
}
point = point.getNext();
}
}
public void out(int k, int m) {//开始数数淘汰
person head = first;//队头指针
person rear = first;//队尾指针
while (true) {//队尾指针到达队尾
if (rear.getNext() == first) {
break;
}
rear = rear.getNext();
}
for (int i = 1; i < k; i++) {//指针到达开始计数的位置
first = first.getNext();
rear = rear.getNext();
}
while (true) {
if (first == rear) {//淘汰完成,剩最后一人
System.out.println("最终留下了的成员为" + first.getNo());
break;
}
for (int j = 1; j < m; j++) {//开始计数
first = first.getNext();
rear = rear.getNext();
}
System.out.println("本轮淘汰的成员为" + first.getNo());
first = first.getNext();
rear.setNext(first);//淘汰该成员
}
}
}
测试方法
class test {
public static void main(String[] args) {
Josephus josephus = new Josephus();
josephus.addperson(10);
josephus.out(5, 3);
}
}
运行结果如下:
总结
1.往环里添加成员的时候,需要辅助指针,第一个成员需要先让自己指向自己。
2.开始技术前,先让队头指针和队尾指针指向对应的位置,然后一起往开始计数的地方移动。
3.在整个过程中,队头元素始终与队尾元素相邻。