Как сделать копию итератора на Java?
у нас есть список элементов и имеют очень упрощенное обнаружение столкновений, где мы проверяем каждый объект на любой другой объект.
проверка коммутативна, поэтому, чтобы не повторять ее дважды, мы бы сделали это на 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);
}
}
ключевым битом здесь является copy
it1 = it0
Как бы вы написали это на Java?
4 ответов
вы не можете копировать итераторы Java, поэтому вам придется делать это без них:
for(int i=0; i<list.size(); i++){
for(int j=i; j<list.size(); j++){
Test(list.get(i), list.get(j));
}
}
вы можете сделать это с помощью 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(n2) (и вы не можете получить лучше, чем это) вместо O(n3), как индекс-доступ в других ответах. (Вы можете быть еще быстрее, если сначала скопируете свой список в массив, но здесь это только постоянный фактор.)
конечно, если вам обычно нужен доступ на основе индекса (или этот итератор-клонирование), вам лучше использовать список на основе массива (или пользовательский список, итератор которого поддерживает клонирование).
для связанного списка(который имеет медленный доступ к индексу), я думаю, что есть способ сделать это без замедления o (n2), о котором упоминал Пауло. Пока вы не заботитесь о порядке посещения списка, вы можете запустить внешний цикл из последнего элемента и выполнить итерацию назад, а также запустить внутренний цикл из первого элемента и выполнить итерацию вперед, пока два итератора не встретятся. См.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);
}
}
for(int i = 0; i < list.size(); i++) {
for(int j = i; j < list.size(); j++){
Test(list.get(i), list.get(j));
}
}