Josephus问题(约瑟夫问题)链表的实现
Josephus问题,下面的游戏:N个人编号从1到N,围坐成一个圈.从1好开始传递一个热土豆.经过M次传递后,拿着热土豆的人被清楚离座,围坐的圈缩紧,由坐在被清除的人后面的人拿着热土豆,继续进行游戏.最后剩下的人取胜.因此,如果M=0和N=5,则游戏人依序被清除,5号游戏人获胜.如果M=1和N=5,那么被清除的人的顺序是2,4,1,5
下面是通过LinkedList实现:
private static void josephus(int m, int n){
LinkedList<Integer> list = new LinkedList<Integer>();
for(int i = 1 ; i <= m; i++){
list.add(i);
}
int loc = 0; // 起始位置
while (true) {
for (Integer x:list)
System.out.print(x + " ");
System.out.println();
int size = list.size();
if (size == 1) {
System.out.println(list.get(0).toString() + ", won!");
return;
} else {
int gap = n % size;
loc += gap;
if(loc >= size){
loc -= size;
}
ListIterator it = list.listIterator(loc);
if (it.hasNext()) {
// it.next();
System.out.println("next remove : " + it.next().toString()); //必须调用到it.next()方法
}
it.remove();
}
}
}
另一种优化后的算法:
public static void pass(int m, int n) {
int i, j, gap, numLeft;
ArrayList<Integer> L = new ArrayList<Integer>();
for (i = 1; i <= m; i++)
L.add(i);
ListIterator<Integer> iter = L.listIterator();
Integer item = 0;
numLeft = m;
for (i = 0; i < m; i++) {
gap = n % numLeft;
if (gap <= numLeft / 2) {
if (iter.hasNext())
item = iter.next();
for (j = 0; j < gap; j++) {
if (!iter.hasNext())
iter = L.listIterator();
item = iter.next();
}
} else {
for (j = 0; j < numLeft - gap; j++) {
if (!iter.hasPrevious())
iter = L.listIterator(L.size());
item = iter.previous();
}
}
System.out.print("removed " + item + " ");
iter.remove();
if (!iter.hasNext())
iter = L.listIterator();
System.out.println();
for (Integer x:L)
System.out.print(x + " ");
numLeft--;
}
}
主要是减少了listIterator的调用次数,只有在边界的时候才调用.