迭代器Java中LinkedList的时间复杂度?

时间:2017-10-09 15:25:05

标签: java linked-list time-complexity

下面的代码将调用迭代器并将整数发送回调用它的方法。我只是想知道如果使用Iterator我的时间复杂度会不变吗? (即O(1))。因为如果我使用带有LinkedList的get,它将给出线性时间(即O(n))。

protected int least(int i) {
    if(i >= digits.size()) {
        return 0;           
    }

    // temp++;
    // System.out.println("Time taken=" + temp);
    // long start = System.nanoTime();

    ListIterator<Integer> itr1 = digits.listIterator(digits.size() - i);

    // System.out.println("Time elapsed:" + (System.nanoTime() - start));

    return itr1.previous();
}

3 个答案:

答案 0 :(得分:3)

迭代器从第i个元素开始

如果您创建的Iterator直接从i的{​​{1}}个索引处开始,则需要知道这也需要LinkedList。在O(n)中查找元素总是

LinkedList 仅记住列表的LinkedList(和head)元素。需要通过遍历整个列表找到所有其他元素。

以下是双重链接列表的说明(Javas tail也是双重链接):

Structure of LinkedList

因此,如果您从LinkedList - 元素开始创建Iterator,则会从i(或head)开始,并按照指向{ {1}} - 元素。这就像打电话:

tail

这显然要花费i

替代方案:ArrayList

如果您需要快速基于索引的访问,也称为随机访问,您可以考虑使用list.get(i); 。它的结构允许在O(n)中访问(它可以通过ArrayList直接计算元素在内存中的位置。)

提供如此快速随机访问的数据结构通常将接口O(1)documentation and implementing classes)作为指标实现。

如何迭代

如上所述,迭代start + i * sizeof(type)不应通过RandomAccess通过基于索引的访问来完成。因此,如果您需要在迭代时修改列表,则应使用LinkedList(或list.get(i)

以下是使用Iterator的常用方法:

ListIterator

或者您也可以使用增强型for循环,它在内部也是如此,但看起来更紧凑:

Iterator

由于Javas Iterator<E> iter = list.iterator(); while (iter.hasNext()) { E element = iter.next(); ... } 双向链接列表,您也可以从尾部开始,然后迭代列表反向。因此,只需使用for (E element : list) { ... } 方法(documentation)代替LinkedList

最后一个示例演示如何在迭代时使用LinkedList#descendingIterator修改列表:

LinkedList#iterator

您还可以使用ListIteratorListIterator<E> listIter = list.listIterator(0); while (listIter.hasNext()) { E element = listIter.next(); ... // Remove the element last polled listIter.remove(); // Inserts an element right before the last polled element listIter.add(new Element()); } 方法使用ListIterator向前和向后遍历列表。这是documentation

答案 1 :(得分:3)

如果您的目的是获取最后一个元素,那么由于LinkedList实现是一个双向链接列表,那么应该有一个对实例可用的尾部和头部的引用,如以及大小。

这意味着List.descendingIterator()可能是一个更好的起点,如果你必须从最后开始,但你总是在O(n)时间内索引到LinkedList结构

如果您经常通过索引取消引用,则通常应使用随机访问结构,例如ArrayList

如果您实际上是在任一方向上遍历列表,那么您应该返回迭代器,而不是值。

答案 2 :(得分:2)

没有

链接列表不能在O(1)时间内随机访问。使用迭代器访问它仍然是O(n)

要理解原因,我们需要深入研究listIterator(int)

的实现
public ListIterator<E> listIterator(int index) {
    checkPositionIndex(index);
    return new ListItr(index);
}

此方法返回一个新的ListItr,让我们看看如何创建它:

    ListItr(int index) {
        // assert isPositionIndex(index);
        next = (index == size) ? null : node(index);
        nextIndex = index;
    }

构造函数调用node,其实现如下:

Node<E> node(int index) {
    // assert isElementIndex(index);

    if (index < (size >> 1)) {
        Node<E> x = first;
        for (int i = 0; i < index; i++) <<<<< HERE!
            x = x.next;
        return x;
    } else {
        Node<E> x = last;
        for (int i = size - 1; i > index; i--) <<<<<< HERE!
            x = x.prev;
        return x;
    }
}

现在你看到了吗? for循环遍历节点一直到索引index的那个节点。这意味着它是O(n)!获取迭代器的速度随着链表中的元素和index的增加而线性增加。