我们有一个元素列表,并且有一个非常简单的碰撞检测,我们检查每个对象与其他所有对象。
检查是可交换的,所以为避免重复两次,我们将在C ++中执行此操作:
for (list<Object>::iterator it0 = list.begin(); it0 != list.end(); ++it0)
{
for (list<Object>::iterator it1 = it0; it1 != list.end(); ++it1)
{
Test(*it0, *it1);
}
}
这里的关键位是副本
it1 = it0
你会怎么用Java写这个?
答案 0 :(得分:7)
您无法复制Java迭代器,因此您必须在没有它们的情况下执行此操作:
for(int i=0; i<list.size(); i++){
for(int j=i; j<list.size(); j++){
Test(list.get(i), list.get(j));
}
}
答案 1 :(得分:6)
您可以使用ListIterator执行此操作:
for(ListIterator<O> outer = list.listIterator(); outer.hasNext() ; ) {
O oVal = outer.next();
for(ListIterator<O> inner = list.listIterator(outer.nextIndex()); inner.hasNext(); ) {
Test(oVal, inner.next());
}
}
对于链接列表(索引访问速度较慢),list.listIterator(index)
仍然需要迭代到正确的位置。
但是这样只有O(n²)(并且你不能比这更好)而不是像其他答案中的索引访问那样的O(n³)。 (如果先将列表复制到数组中,可能会更快,但这只是一个常数因素。)
当然,如果您通常需要基于索引的访问(或此迭代器克隆),您最好使用基于数组的列表(或迭代器支持克隆的自定义列表)。
答案 2 :(得分:4)
对于一个链表(索引访问速度慢),我认为有一种方法可以做到这一点,而不会引起Paŭlo提到的O(n²)减速。只要您不关心访问列表的顺序,就可以从最后一个元素开始外循环并迭代回来,从第一个元素开始内循环并向前迭代直到两个迭代器相遇。请参阅以下代码中的iterRevIterator
。对list.listIterator(list.size())
的调用很快,因为list
是LinkedList
,即双向链表,并且访问最后一个元素不需要遍历列表。
差异并不大......
iterIndex: 384.59ms sum=29656666
iterIterator: 1.91ms sum=29656666
iterRevIterator: 1.55ms sum=29656666
但仍然很重要。
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.ListIterator;
public class TestIter {
public static int iterIndex(List<Integer> list) {
int sum = 0;
for(int i = 0; i < list.size(); ++i) {
for(int j = i+1; j < list.size(); ++j) {
sum += list.get(i) * list.get(j);
}
}
return sum;
}
public static int iterIterator(List<Integer> list) {
int sum = 0;
for(ListIterator<Integer> outer = list.listIterator(); outer.hasNext() ; ) {
Integer oVal = outer.next();
for(ListIterator<Integer> inner = list.listIterator(outer.nextIndex()); inner.hasNext(); ) {
sum += oVal * inner.next();
}
}
return sum;
}
public static int iterRevIterator(List<Integer> list) {
int sum = 0;
for(ListIterator<Integer> outer = list.listIterator(list.size()); outer.hasPrevious() ; ) {
Integer oVal = outer.previous();
for(ListIterator<Integer> inner = list.listIterator(); inner.nextIndex() <= outer.previousIndex(); ) {
sum += oVal * inner.next();
}
}
return sum;
}
public static void main(String[] args) {
int size = 1000;
int rep = 100;
int sum = 0;
// List<Integer> list = new ArrayList<Integer>();
List<Integer> list = new LinkedList<Integer>();
for (int i = 0; i < size; ++i) {
list.add(i);
}
long startTime = System.currentTimeMillis();
for (int i = 0; i < rep; ++i) {
sum = iterIndex(list);
}
System.out.println("iterIndex: " + (float)(System.currentTimeMillis() - startTime)/rep + "ms sum=" + sum);
startTime = System.currentTimeMillis();
for (int i = 0; i < rep; ++i) {
sum = iterIterator(list);
}
System.out.println("iterIterator: " + (float)(System.currentTimeMillis() - startTime)/rep + "ms sum=" + sum);
startTime = System.currentTimeMillis();
for (int i = 0; i < rep; ++i) {
sum = iterRevIterator(list);
}
System.out.println("iterRevIterator: " + (float)(System.currentTimeMillis() - startTime)/rep + "ms sum=" + sum);
}
}
答案 3 :(得分:1)
for(int i = 0; i < list.size(); i++) {
for(int j = i; j < list.size(); j++){
Test(list.get(i), list.get(j));
}
}