一、问题背景
有30个人围成一个环,需要将其中的15个选出来杀掉,规则是,从第一个开始数1,把数到9的那个杀了,接着下一个重新从1开始数,如此循环,直到最后剩15个,这15个幸运儿的编号是分别是多少?
二、基本思路
一开始我想着用数组解决这个问题,然而发现用数组做太麻烦了,每次杀掉一个人,也就是删除一个节点都需要把后面的所有元素都往前移动,所以,我想到的用链表中的循环双向链表,这样一来,在删除一个节点时,只需要将该节点的上一个节点的下一个指向该节点的下一个,下一个节点的上一个指向该节点的上一个就可以了,说得有点乱,举个例子
A < > B < > C,为了删除B节点,需要以下步骤:A.next=C ; C.pre=A(缺一不可)
这样也就比较真实的模拟了问题场景
三、代码实现
public class Joseph {
public static void main(String[] args) {
People[] peoples=new People[30];
initCircle(peoples);//初始化循环链表,将头尾相接
int count=0;
People peopleRange=peoples[0];//轮到数数的人
while(People.sum>15){
count++;
peopleRange=peopleRange.nextPeople;
if(count==8){//数到第九个
System.out.println("删除第"+peopleRange.number+"号");
peopleRange.prePeople.nextPeople=peopleRange.nextPeople;
peopleRange.nextPeople.prePeople=peopleRange.prePeople;//在将中间节点删除时,既要把前一个指向后一个,也要把后一个指向前一个
People.sum--;
count=-1;
showRemain(peopleRange);//输出剩余的人的号数
}
}
}
private static void showRemain(People peopleRange) {
int i=People.sum;
People t=peopleRange.nextPeople;
System.out.println("剩余的人为:");
while(i>0){
System.out.print(t.number+" ");
t=t.nextPeople;
i--;
}
System.out.println();
}
private static void initCircle(People[] peoples) {
for(int i=0;i<30;i++){
peoples[i]=new People();
peoples[i].number=i;
}
for(int i=0;i<30;i++){
if(i==29){
peoples[i].nextPeople=peoples[0];
break;
}
peoples[i].nextPeople=peoples[i+1];
}
for(int i=29;i>=0;i--){
if(i==0){
peoples[i].prePeople=peoples[29];
break;
}
peoples[i].prePeople=peoples[i-1];
}
}
}
class People{
static int sum=30;
int number;
People nextPeople;
People prePeople;
}
四、效果与总结
运行结果
删除第8号
剩余的人为:
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 0 1 2 3 4 5 6 7
删除第17号
剩余的人为:
18 19 20 21 22 23 24 25 26 27 28 29 0 1 2 3 4 5 6 7 9 10 11 12 13 14 15 16
删除第26号
剩余的人为:
27 28 29 0 1 2 3 4 5 6 7 9 10 11 12 13 14 15 16 18 19 20 21 22 23 24 25
删除第5号
剩余的人为:
6 7 9 10 11 12 13 14 15 16 18 19 20 21 22 23 24 25 27 28 29 0 1 2 3 4
删除第15号
剩余的人为:
16 18 19 20 21 22 23 24 25 27 28 29 0 1 2 3 4 6 7 9 10 11 12 13 14
删除第25号
剩余的人为:
27 28 29 0 1 2 3 4 6 7 9 10 11 12 13 14 16 18 19 20 21 22 23 24
删除第6号
剩余的人为:
7 9 10 11 12 13 14 16 18 19 20 21 22 23 24 27 28 29 0 1 2 3 4
删除第18号
剩余的人为:
19 20 21 22 23 24 27 28 29 0 1 2 3 4 7 9 10 11 12 13 14 16
删除第29号
剩余的人为:
0 1 2 3 4 7 9 10 11 12 13 14 16 19 20 21 22 23 24 27 28
删除第11号
剩余的人为:
12 13 14 16 19 20 21 22 23 24 27 28 0 1 2 3 4 7 9 10
删除第23号
剩余的人为:
24 27 28 0 1 2 3 4 7 9 10 12 13 14 16 19 20 21 22
删除第7号
剩余的人为:
9 10 12 13 14 16 19 20 21 22 24 27 28 0 1 2 3 4
删除第21号
剩余的人为:
22 24 27 28 0 1 2 3 4 9 10 12 13 14 16 19 20
删除第4号
剩余的人为:
9 10 12 13 14 16 19 20 22 24 27 28 0 1 2 3
删除第22号
剩余的人为:
24 27 28 0 1 2 3 9 10 12 13 14 16 19 20
总结
在做这道题的过程中,由于漏了删除节点的后面一步,也就是下一个节点与前一个节点“拉”上,这在后续的数数过程会
出现前一个已经被删除的节点又在次出现的蜜汁bug,这个bug看了我好一段时间,结论:看问题要严谨,粗心是病,要治!