如何在 Java 中复制迭代器?

发布于 2024-11-06 19:49:24 字数 396 浏览 1 评论 0原文

我们有一个元素列表,并有一个非常简单的碰撞检测,我们将每个对象与其他对象进行检查。

检查是可交换的,因此为了避免重复两次,我们将在 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 中编写此操作?

We have a list of elements and have a very simplistic collision detection where we check every object against every other object.

The check is commutative, so to avoid repeating it twice, we would do this in 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);
    }
}

The key bit here is the copy

it1 = it0

How would you write this in Java?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

迷荒 2024-11-13 19:49:25

您可以使用 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³) 。 (如果您首先将列表复制到数组中,您可能会更快,但这只是一个常数因子。)

当然,如果您通常需要基于索引的访问(或此迭代器克隆),您最好使用基于数组的列表(或其迭代器支持克隆的自定义列表)。

You can do this with 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());
    }
}

For a linked list (which has slow index access) the list.listIterator(index) still needs to iterate to the right place, though.
But this way it is only O(n²) (and you can't get better than this) instead of O(n³) like the index-access in the other answers then. (You might be even faster if you copy your list first to an array, but it is only a constant factor here.)

Of course, if you usually need index-based access (or this iterator-cloning), you would better use an array-based list (or a custom list whose iterator supports cloning).

虫児飞 2024-11-13 19:49:25

您无法复制 Java 迭代器,因此您必须在没有它们的情况下执行此操作:

for(int i=0; i<list.size(); i++){
    for(int j=i; j<list.size(); j++){
        Test(list.get(i), list.get(j));
    }
}

You cannot copy Java iterators, so you'll have to do it without them:

for(int i=0; i<list.size(); i++){
    for(int j=i; j<list.size(); j++){
        Test(list.get(i), list.get(j));
    }
}
遮了一弯 2024-11-13 19:49:25

对于链表(索引访问速度较慢),我认为有一种方法可以做到这一点,而不会导致 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);

    }

}

For a linked list (which has slow index access), I think there is a way to do it without incurring in the O(n²) slowdown that Paŭlo mentioned. As long as you don't care about the order the list is visited, you can start the outer loop from the last element and iterate back, and start the inner loop from the first element and iterate forward until the two iterators meet. See iterRevIterator in the code below. The call to list.listIterator(list.size()) is fast because list is a LinkedList, i.e. a doubly-linked list, and accessing the last element does not require iterating through the list.
The difference is not enormous...

iterIndex: 384.59ms sum=29656666
iterIterator: 1.91ms sum=29656666
iterRevIterator: 1.55ms sum=29656666

but still significant.

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);

    }

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文