简体   繁体   English

LinkedList 的 add(int, E) 的 O(1) 复杂度如何?

[英]How is LinkedList's add(int, E) of O(1) complexity?

From the tag wiki excerpt:标签 wiki 摘录:

A linked list is a data structure in which the elements contain references to the next (and optionally the previous) element.链表是一种数据结构,其中元素包含对下一个(和可选的前一个)元素的引用。 Linked lists offer O(1) insert and removal at any position , O(1) list concatenation, and O(1) access at the front (and optionally back) positions as well as O(1) next element access.链接列表在任何 position 处提供 O(1) 插入和删除,O(1) 列表连接,O(1) 访问前面(和可选的后面)位置以及 O(1) 下一个元素访问。 Random access has O(N) complexity and is usually unimplemented.随机访问的复杂度为 O(N),通常未实现。

(emphasis mine) (强调我的)

I was surprised to read this – how can the list insert at a random index with a lower complexity than simply reading that index?我很惊讶地读到这个——列表如何插入一个随机索引,而不是简单地读取该索引的复杂性?

So I looked at the source code for java.util.LinkedList .所以我查看java.util.LinkedList的源代码 The add(int, E) method is: add(int, E)方法是:

public void add(int index, E element) {
    addBefore(element, (index==size ? header : entry(index)));
}

The addBefore(E, Entry<E> method is simply pointer reassignment, but there's also the entry(int) method : addBefore(E, Entry<E>方法只是指针重新分配,但还有entry(int)方法

if (index < 0 || index >= size)
        throw new IndexOutOfBoundsException("Index: "+index+
                                            ", Size: "+size);
    Entry<E> e = header;
    if (index < (size >> 1)) {
        for (int i = 0; i <= index; i++)
            e = e.next;
    } else {
        for (int i = size; i > index; i--)
            e = e.previous;
    }
    return e;
}

Even with the half-size optimization, the for loop in here (one or the other) seems to me a dead giveaway that this method (and thus add(int, E) ) operates in a minimum worst-case scenario of O(n) time, and certainly not constant time.即使进行了一半大小的优化,这里的for循环(一个或另一个)在我看来似乎是一个致命的赠品,即这种方法(因此add(int, E) )在 O(n) 的最小最坏情况下运行) 时间,当然不是常数时间。

What am I missing?我错过了什么? Am I misunderstanding the big-O notation?我误解了大 O 符号吗?

This is because the article that you are reading considered "getting to that index" as a separate operation. 这是因为您正在阅读的文章将“转到该索引”视为单独的操作。 The article assumes that you are already at the index you wish to perform add(int, E). 本文假设您已经处于要执行的索引add(int,E)。

To conclude: 总结:

Insert or Remove operation = O(1) 插入或删除操作= O(1)

Finding node at n th index = O(n) n 索引处查找节点= O(n)

Well, they do support constant-time inserts at arbitrary positions – but only if you happen to have a pointer to the list entry after which or in front of which you want to insert something. 好吧,它们确实支持在任意位置进行常量插入 - 但前提是你碰巧有一个指向列表条目的指针,之后或者在其前面插入一些东西。 Of course, this won't work if you just have the index, but that's not what you usually do in optimized code. 当然,如果你只有索引,这将不起作用,但这不是你通常在优化代码中做的。

In Java, you can do that, too, but only using a list iterator . 在Java中,您也可以这样做,但只能使用列表迭代器

This property of linked lists is their biggest advantage compared to arraylists or so – for example, if you want to remove a user from the user list of a chatroom, you can store a pointer to the user's position in the userlist in the user so that, when he wants to leave the room, that can be implemented as a O(1) operation. 与arraylists相比,链接列表的这一属性是它们的最大优势 - 例如,如果要从聊天室的用户列表中删除用户,则可以在用户列表中存储指向用户位置的指针,以便,当他想要离开房间时,可以实现为O(1)操作。

The operation of linking the new node to any node is O(1) but the operation of finding (helps to the loop) the concerned index is definitely O(n). 将新节点链接到任何节点的操作是O(1),但查找 (有助于循环)相关索引的操作肯定是O(n)。

There is no magic ;) 没有魔法;)

The wiki page you quote says: 你引用的wiki页面说:

O(1) insert and removal at any position O(1)在任何位置插入和移除

Then you ask: 然后你问:

I was surprised to read this – how can the list insert at a random index 我很惊讶地看到这个 - 如何在随机索引中插入列表

Herein lies the confusion: the terms position and index are not being used to mean the same thing. 这就是混乱:术语位置索引并不是用来表示相同的东西。 The wiki talks about an iterator or a pointer, not about an index. wiki讨论迭代器或指针,而不是索引。

for the ones who find this question via google and wondering what the complete answer for add(index, elem) is.对于那些通过谷歌找到这个问题并想知道 add(index, elem) 的完整答案是什么的人。

It is:这是:

finding element + insert
    O(index)    +  O(1)

It's not O(n) + O(1) because you only iterate to the index and not all elements of the list.它不是 O(n) + O(1) 因为您只迭代到索引而不是列表的所有元素。

Hope this helps.希望这可以帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM