约瑟夫环问题(循环链表实现)

一、问题背景

有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看了我好一段时间,结论:看问题要严谨,粗心是病,要治!

猜你喜欢

转载自blog.csdn.net/andy_budd/article/details/81129074