7

I am pushing n entries into Java LinkedList at O(1).
There are few unique items i would like to remove later on at O(1).
I though about keeping an array with "pointers" to the unique nodes at the LinkedList so i can later on remove them.
is there a way to do it on LinkedList or any other java class?
I tried storing iterators to the items. So i can use iter.remove(). But i understood that there can be only one iterator on a list at the time.

I know that an easy solution could be implementing link list on my own. But i rather use LinkedList or some other Java class already implemented.

Steve Kuo
  • 58,491
  • 75
  • 189
  • 247
Roy
  • 221
  • 3
  • 8
  • "But i understood that there can be only one iterator on a list at the time." That's not true. – Louis Wasserman Jan 22 '14 at 21:24
  • 2
    @LouisWasserman Even if he could have multiple iterators, would it help? "if the list is structurally modified at any time after the iterator is created, in any way except through the `Iterator`'s own remove or add methods, the iterator will throw a `ConcurrentModificationException`". Seems like if he removes an element using `iter.remove` on one iterator, all the others would then become unusable. – ajb Jan 22 '14 at 21:30
  • @ajb: Yes, you'd have to do all this manipulation through a single iterator, but you couldn't do it if the elements were noncontiguous and you had more than one to deal with. – Louis Wasserman Jan 22 '14 at 21:39
  • @LouisWasserman "but you couldn't do it if the elements were noncontiguous and you had more than one to deal with" - thats exactly the case. – Roy Jan 23 '14 at 08:30

2 Answers2

5

The Java List implementations do not offer O(1) performance on removes*. Using an iterator you have to traverse to the index ( O(n) ), with an ArrayList you have an after-remove shift ( O(n) ), and even though LinkedList is a doubly-linked list, it does not expose the nodes in the list for you to be able to remove them directly by simply reassigning the next/last references - a traversal is required to find the node to remove ( O(n) ).

You could write your own MyDoublyLinkedList<MyNode<T>> that did so, exposing the nodes rather than the values contained within, which would allow for O(1) removals if you retained a reference to the node. Indexing is of course O(n) to get something from the list by index. Depending on your use patterns it may be a viable design choice.

Short of that, if you want to use the data structures provided by Java, use a data structure that provides that performance:

If ordering isn't important and there are no duplicate items, use a HashSet (note, however, this does not allow direct indexing at all)

Otherwise, reworking your code to use a Map implementation is probably your best bet.

[*] LinkedList and the Deque implementations are O(1) for head/tail removal.

Edit to add from comments:

As mentioned above, no, there is no O(1) time complexity remove operation.

The reason for this is that except in the most extreme edge cases, it's irrelevant.

On my 5 year old, 3Ghz desktop it takes .2ms (point-two) for the worst-case O(n) removal on a LinkedList with 100,000 entries via an index (that is to say, index = length/2)

I start running into windows swapiness disk I/O due to windows memory management on this box if I up it to 1,000,000 entries.

In short, you're trying to solve a problem that doesn't exist in most cases. This is generally called "Premature Optimization"

Brian Roach
  • 72,790
  • 10
  • 128
  • 154
-2

The problem with storing a pointer to the item you wish to remove is that removing an item from a linked list requires knowledge of the item preceding the item you wish to remove as well.

A LinkedList is not designed for removing specific items at low cost - you should re-evaluate what List you use (an ArrayList removes in O(1)). Is there any reason you want a LinkedList?

user2282497
  • 191
  • 1
  • 9
  • 4
    It's debatable that an ArrayList removes in O(1), it has to shift everything back down which is relegated to the native System.arraycopy method. depending on how this is implemented, it may well be O(n) – Sinkingpoint Jan 22 '14 at 21:38
  • it uses System.arraycopy() to shift. That cost is constant against the size of the list, so O(1). – evanchooly Jan 22 '14 at 22:01
  • 2
    The _size of the list_ is `n`, therefore O(n) worst case. – GriffeyDog Jan 22 '14 at 22:08
  • 1
    An `Arraylist` simply moves where the cost occurs, but has the same performance; it doesn't traverse to find the element, but it has to shift everything after. Both are O(n). – Brian Roach Jan 22 '14 at 22:22
  • 1
    To be clear, a `LinkedList` in Java is a *doubly* linked list. Removing items from a dll is efficient if you have a reference to the node; it's O(1). Java just doesn't allow you access to the nodes to do so. – Brian Roach Jan 22 '14 at 22:49
  • @evanchooly `System.arrayCopy()` isn't magic just because it's using the native `memmove()` call. The operation is directly (and linearly) size dependent (number of bytes to move), therefore O(n). – Brian Roach Jan 22 '14 at 23:27
  • No, it isn't magic. But its performance is not strictly tied to the size of the list. It does 1 operation to move those elements. That's O(1). – evanchooly Jan 23 '14 at 14:54
  • 1
    Lol, No,really, it is, and its O(n) see: http://stackoverflow.com/questions/2710002/should-i-consider-memmove-on-or-o1 you seem to not understand that a single native call != O(1) – Brian Roach Jan 23 '14 at 21:23
  • There are many cases which you want to maintain a linkedlist and still be able to remove a node with O(1). An example of that is implementing a LRU using a hashmap and linkedlist. OP question is valid. – apadana May 20 '16 at 02:54