我在ArrayList中有一些对象,我想执行碰撞检测等。可以这样做:
List<Person> A;
iterA0 = A.iterator();
while (iterA0.hasNext()) {
Person A = iterA.next();
iterA1 = A.iterator();
while (iterA1.hasNext()){
Person B = iterA1.next();
A.getsDrunkAndRegretsHookingUpWith(B);
}
}
那要编码很糟糕,对吧?我该如何适当地执行这个嵌套迭代?
答案 0 :(得分:4)
您可以同时多次迭代同一个列表,只要它在任何迭代期间都没有被修改。例如:
List<Person> people = ...;
for (Person a : people) {
for (Person b : people)
a.getsDrunkAndRegretsHookingUpWith(b);
}
只要getsDrunkAndRegretsHookingUpWith
方法不会更改people
列表,这一切都很好。
答案 1 :(得分:2)
这是经典握手问题的一个例子。在一个满n
人的房间里,n
选择2
种不同的握手。你无法避免二次运行时。
@Chris' answer向您展示了更好的代码编写方式。
Re:OP评论
我一直在做的是一些代码,其中一个事件导致粒子爆炸,导致所有附近的粒子爆炸......链式反应。对象存储在一个列表中,如果非爆炸粒子位于爆炸粒子的定义半径范围内,则它们仅会爆炸。所以我可以调整一些条件来使它更快一点,但仍然需要n ^ 2遍历。
答案 2 :(得分:0)
那要编码很糟糕,对吧?
大多数人可能会同意,如果您使用的是Java 5+,并且没有特别需要公开迭代器对象,那么您应该使用“for each”循环来简化代码。但是,这应该对性能没有影响,当然也不会对复杂性产生影响。
不必要地暴露迭代器肯定不是可怕的编程。在1到10的不良编码风格的范围内,这只是1或2.(并且任何告诉你的人最近都没有看到任何真正可怕的编码......)
那么如何自己做n ^ 2?
你原来的问题过于设计,无法回答这个问题。
根据真实关系的含义,您可以利用对称性/反对称性或关联性来减少工作量。
但是,如果没有该信息(或其他域信息),您无法改进此解决方案。
对于您的真实示例(涉及粒子),您可以通过将屏幕划分为区域来避免O(N^2)
比较问题;例如使用四叉树。然后迭代相同和相邻区域中的点。
答案 3 :(得分:0)
如果在您的情况下,可以减少迭代次数:
A.getsDrunkAndRegretsHookingUpWith(B)
也暗示B.getsDrunkAndRegretsHookingUpWith(A)
,A.getsDrunkAndRegretsHookingUpWith(A)
始终相同然后代替使用迭代器或foreach,您可以采用更传统的方法并排除与自身的碰撞,并且已经进行了带有withc比较的元素。
List<Person> people;
for (int i=0; i<people.size(); i++){
a = people.get(i);
for (int j=i+1; j<people.size();j++){ // compare with next element and onwards in the list
a.getsDrunkAndRegretsHookingUpWith(people.get(j)); // call method
}
}