Reputation:
Why does the following java code result in an infinite loop?
import java.util.LinkedList;
import java.util.Random;
public class Main {
public static void main(String[] args) {
int n = 3;
Random rand = new Random();
LinkedList<Integer> fields = new LinkedList<Integer>();
for (int i = 0; i < n*n; i++) {
fields.add(i);
}
while (fields.size() > 0) {
// Choose Field
int f = rand.nextInt(fields.size());
fields.remove((Integer) f);
System.out.println(fields.size());
}
}
}
Upvotes: 4
Views: 174
Reputation: 477040
The way you use remove
, you remove objects by value, not by position.
Say your list consists of values [0, 1, 2, 3]
, and you remove 0
and 1
the first two times. Now you have [2, 3]
, whose size is 2, so you will never remove 3
now!
To remove by position rather than value, say fields.remove(f)
. (Notice that f
is an integer, while (Integer)f
is an object of the type contained in the list container.)
(Alternatively, for different behaviour, you could continue removing by value, but you should now draw the random number from the range [min, max]
, where you have to determine the extremal values of the list elements separately. This may take a lot longer, of course, since you will have a lot of "misses" where you don't remove anything.)
Upvotes: 11
Reputation: 298898
Because of this line:
fields.remove((Integer) f);
Remove the (Integer)
cast and it should work.
There are two flavors of remove in List:
remove(int)
andremove(E)
(actually it's remove(Object)
for compatibility reasons)In your case, E is Integer, and because of autoboxing you are able to cast an int to an Integer. And by doing that, you are choosing the second type, whereas you want the first type.
Upvotes: 5
Reputation: 53829
You problem comes from the fact that you are actually calling the remove(Object o) method instead of the remove(int index) method!
When you call fields.remove((Integer) f);
you do not remove the object at the index f
but you remove the Integer that is equal to f
since your List contains Integer
s
Therefore do not cast f
into Integer
and you should be fine.
Also, to get an Integer
from an int
, use the static Integer valueOf(int i) method.
Upvotes: 2
Reputation: 533520
Stepping through the debugger I can see the problem you have is that you are removing numbers which less than the size. To start with that number will be there however, unless you remove the largest number the first time it will never be removed.
What you are trying to do is to select numbers in a random order. The simplest way to do this is to use Collections.shuffle()
int n = 3;
List<Integer> list = new LinkedList<Integer>();
for (int i = 0; i < n * n; i++)
list.add(i);
Collections.shuffle(list);
System.out.println(list);
prints
[7, 4, 0, 8, 5, 1, 3, 6, 2]
Upvotes: 0
Reputation: 46395
import java.util.LinkedList;
import java.util.Random;
public class Main {
public static void main(String[] args) {
int n = 3;
Random rand = new Random();
LinkedList<Integer> fields = new LinkedList<Integer>();
for (int i = 0; i < n*n; i++) {
fields.add(i);
}
while (fields.size() > 0) {
// Choose Field
int f = rand.nextInt(fields.size());
fields.remove(f);
System.out.println(fields.size());
}
}
}
Upvotes: 1