I was reading a thread here about the performance of java ArrayList and LinkedList. There is an answer from Mr Kevin Brock that reads the following.
"Linked list add is not always O(1)
[or this should say addLast() is
O(1)]. This is only true if done from
within a ListIterator. The add methods
in Java's LinkList implementation must
search through the list if additions
are not on the head or tail."
I din't understand what he meant by "only if done through ListIterator". Does it mean there is a data structure within the linkedlist that holds the reference of each index and as soon as we get the listiterator from a certain index, listiterator is returned straight away without walking through the list to find that index?
Thanks guys!
It means that iterator points to list nodes directly; and so access via get(int) will be O(N), but iterator.next() wil be O(1). Latter has direct reference and does not need to traverse anything; former will need to traverse from head of the list.
If you add to a LinkedList where the ListIterator is pointing to, it is O(1). This is the same as adding to the start of the LinkedList or the end of an ArrayList.
The comment refers to the two argument add method, [add(int,E)][1]. Assuming a linearly distributed index, then this will be O(n) as the list needs to be iterated through to find the appropriate node. It does not apply to add(E).
[1]: http://download.oracle.com/javase/6/docs/api/java/util/LinkedList.html#add(int, E)
Related
Is it Linear Time or Constant Time and why? Is it linear because the first element is on the bottom? Or is it constant because of traversal in linked list?
Confused and seeking explanation. Using Java
Java's LinkedList is a doubly ended queue that maintains a pointer to the first and last element. Anytime you try to get the last element of the LinkedList, it can be directly accessed as it already has a pointer to it. So for getting the last element the time complexity is O(1).
It also has a method getLast() to retrieve the last element.
Your question is ambiguous:
The java.util.Stack class not a linked list. It is actually a subtype of Vector and uses an array internally rather than a linked list.
In general terms, a "stack" is an abstraction: an API. We can't make definite statements about the complexity of a "stack" without tying them to a specific implementation.
Even saying "a stack implemented as a linked list" is not sufficient because you could use a linked list to implement a stack in many ways. There is an obvious way to do it ... and there are other ways with varying performance characteristics.
It is also unclear what you mean by "first" and "bottom". I think I have figured it out, but if you are asking questions that need a precise answer, the questions themselves should be precise!
So ... lets make some assumptions:
Assume that the "bottom" element is the one that will be popped last if you pop all of the elements of a stack.
Assume that the stack is not java.util.Stack but a reasonable implementation using linked lists; i.e. push() is implemented as adding a new node to the start of the list, and pop() is implemented as removing the node at the start of the list.
The complexity of push() and pop() will be O(1).
So what is the complexity of retrieving the "bottom" element of the stack?
Well, if you follow the linked list chain of a stack with N elements, you have N links to traverse to get to the list node for the "bottom" element; i.e. O(N).
But if your stack implementation also keeps a pointer to the last list node, you can get the "bottom" list node in O(1). (Would you do that? Well it depends if you are going to need to get the bottom element frequently!)
Note that the above analysis applies for both singly and doubly linked lists.
Note that if we were talking about an array based stack, the code for getting the bottom element would be roughly equivalent to:
get_bottom() {
return this.array[this.bottom]
}
That is O(1)
My aim is to delete a node somewhere in the middle of a Java LinkedList object, in O(1) time.
If I can get a reference to the node, I could probably do this myself without the need for a Java-provided method. But I cannot seem to find a way to get a reference to anything but the head of the list.
How can I get a reference to the last node in a Java LinkedList object? I wold then store these references in a map to use later.
Note: I know this is doable if I implement my own LinkedList, but is there a way to do it with Java's LinkedList class?
I would suggest actually changing your data structure to LinkedHashSet here instead of LinkedList. The reason for this is that LinkedHashSet#get() and remove() can lookup or delete any element by key in O(1) time. Also, a LinkedHashSet is implemented with a linked list running through the entries. The order of the entries while iterating the list are determined by the insertion order, so it behaves similarly to a LinkedList in that regard.
The closest thing you can get to a direct reference is an Iterator that points to a specific point.
If you call remove() on such an Iterator it should work in O(1):
LinkedList<Object> linkedList = ...;
Iterator<Object> it = linkedList.iterator();
while (it.hasNext()) {
if (matchesSomeCondition(it.next()) {
it.remove();
}
}
Note that this sample code definitely doesn't run in O(1), it's specifically just the remove() call that can have that efficiency. If you haven't already identified the node in some way (such as positioning an Iterator at that place), then you won't be able to remove an element from a LinkedList in O(1) time.
Edit and since you mention "last recently added" element then maybe a ListIterator is the thing to use, since it has an add() method. If you can efficiently implement all your adding/removing using a ListIterator, then you can keep the traversal operations over the LinkedList to a minimum. In fact, if you always use indexes to add/remove objects from your LinkedList then you loose a lot of its efficiency (since each add/remove call has to find the affected item first via traversal).
I have an algorithm where I pass through nodes in a graph in a certain way, occasionally passing through the same node several times, and I need to form a list of the nodes passed, such that a node appears once for the last time I passed it.
For instance, if I passed through nodes A -> B -> C -> A -> C, the list I need in the end is [B, A, C].
What I wanted to do was to use a LinkedList, such that every node in the graph will contain a reference to its node in the LinkedList. Then, every time I pass through a node, I will remove its corresponding node from the LinkedList and insert it again into the end of the LinkedList, and the complexity of the operation will only be O(1).
However, when I began implementing this, I ran into a problem: apparently, the java class LinkedList does not allow me to see its actual list nodes. Using the regular remove functions of LinkedList to remove the list node containing a given graph node will be O(n) instead O(1), negating the whole point of using a LinkedList to begin with.
Naturally, I can implement LinkedList myself, but I would rather avoid that - it seems to me that if I have to implement LinkedList in java, I'm doing something wrong.
So, is there a way to solve this problem without implementing LinkedList on my own? Is there something that I'm missing?
As it seems, you are expecting a built-in approach, i don't think there is any Collection which provides such functionality. You will have to implement it on your own as #MartijinCourteaux suggested. Or:
use Sorted Set collection like TreeSet<E> with supporting cost of O(log n) for operations: add, remove and contains.
LinkedHashSet<E> But beware unlike HashSet<E>, LinkedHashSet can have O(1) expected performance for operations: add, contains, remove but the performance is likely to be just slightly below that of HashSet, due to the added expense of maintaining the linked list. But we can use it without incurring the increased cost associated with TreeSet. However, insertion order is not affected if an element is re-inserted into the set so try removing the first insertion of an element before re-inserting it.
LinkedHashMap keeps order of entered values and allows remove node by its key and then put back to the end. I think that it is all you need.
Unless your linked list is large just using a regular array list will give fast performance even with the shuffling. You should also consider using hash sets, if order is not important, linked hash set if the order of insert matters, or tree set if you want it sorted. They don't allow duplicate values but have good O performance for insert, delete and contains.
In the implementation of HashMap, linked lists are used to represent elements in buckets.
Each Entry has a element to the next Entry. See: Ref. However, in the implementation for the LinkedList class, each element has a reference to its previous element and its next element see Ref. Just trying to figure out why previous is important in one linked list and not another?
Entry (internal class of HashMap) is not a part of general-use linked list (as LinkedList is). It's sole purpose is to iterate over it in forward direction looking for an element. So it does not need a previous reference.
the previous reference make the LinkedList a bidirectional List,this makes it possible to reversely iterate on a List .
The reference to the previous element is not needed in a linked list, stricly speaking. The java.util.LinkedList is actually a doubly-linked list. This is needed for an efficient implementation of the following operations:
add(E), which append at the end of the list;
getLast(), which retrieves the last element of the list;
ListIterator.previous() which allow traversal of the list in reverse order.
Said operations are of no use for the linked list of Map.Entry.
Note that while getLast() is a LinkedList adition to the list interface, the two other are required by the said interface.
The LinkedList is a general-purpose implementation. You may want to iterate over it backwards. For Maps, when searching a bucket it only iterates forward. Since there is not need to iterate backward, it is not implemented.
According to this posting, it is said that ListBuffer allows constant-time removal of the first and last elements. I've been looking into the API reference and the ListBuffer source code, but I can't find how I remove the last element in constant time while remove(0) will do the job for the first element. What would be the proper way to remove the last element?
Another question: is it possible to remove an element efficiently while iterating over a ListBuffer? In Java it can be done with Iterator.remove() but the Scala iterator doesn't seem to have the remove() method...
The first question has an easy if disappointing answer: you can't remove the last element in constant time, as doing so would require a reference to the element-before-last. (It's a singly linked list, inside a wrapper class that holds the beginning and end elements of the list.)
The second question is equally easy and perhaps disappointing: Iterators in Scala are simply views of the collection. They don't modify the underlying collection. (This is in keeping with the "immutable by default, mutable only when necessary" philosophy.)
You can remove the last element with trimEnd(1)