LinkedList is a data structure, in which each element is coupled with a link to its next element.
So, in theory, this data structure is made for freely iterating through a list, in whichever direction, while performing whatever operations (except, maybe, deleting the element you're currently at).
However, in application, this isn't true. Returning an Iterator from a LinkedList is subject to the general Iterator rules (i.e. no modifying while iterating), and even creating a ListIterator, an improved Iterator, which allows modifying the next/previous element of the iterator, and let's you go forward/backward dynamically, still has severe limitations:
You can't delete elements from the beginning of the list if you're not currently there, and neither can you add elements to the end of the list, unless you're currently there.
So, is there a way to iterate freely through a LinkedList while performing whatever modifications to the list? And if not, why isn't there one? Shouldn't it be one of the main goals of this data structure to realize it?
The choice to make all Iterators failfast was a design decision, just that and nothing more.
Nothing stops you to take the code and starting from that, build a NotSoFailFastIterator for yourself if you think you can use it. However I think you'll quickly revert from using it once yoy see its behaviour and its results in usage scenarios where there's really lots of concurrent activity going on on the underlying List of your iterator.
This behavior is not specific to LinkedLists. When you iterate over a List (any List) with a ListIterator, you can only make structural changes (adding or removing elements) in the current position of the iterator. Otherwise, continuing to use the iterator after a structural change of the List may yield unexpected results.
For adding elements to the start or end of the LinkedList, you have addFirst and addLast methods. You don't have to iterate over the List in order to do that.
A ListIterator instance maintains a state that allows it to locate the next and previous elements as well as support other operations (remove the current element, add an element at the current position). If you make a structural change to a List not via the ListIterator, the state of the iterator may become invalid, leading to unexpected results. Therefore all structural changes must be made via the ListIterator.
I guess that the LinkedList class could supply an implementation of a more complex iterator that supports operations such as addFirst and addLast. I'm not sure how useful that would have been, and whether it would justify the added complexity.
If you want to iterate freely use array or list. Linked lists are meant to be traversed and access the data useful in dynamic allocation of the memory to the data.
When you have a linked list datastructure, you can add or remove at a particular node, when your cursor is pointing to the right node where you want to add or remove.
Inserts the specified element into the list (optional operation). The
element is inserted immediately before the element that would be
returned by next(), if any, and after the element that would be
returned by previous(), if any. The new element is inserted before
the implicit cursor: a subsequent call to next would be unaffected,
and a subsequent call to previous would return the new element. (This
call increases by one the value that would be returned by a call to
nextIndex or previousIndex.)
ListIterator
Instead if its a array structure, then you access by index , and it is possible to add or remove at a particular index limited , by the length of the array. ArrayList does that.
Related
I have a LinkedList. Suppose that I'm inserting an element at the end and I want to save the position where was it inserted, so that I can call a function on an element next to it, whatever manages to get into this collection later. Is it possible with Java iterators? Many thanks.
Just to recollect, I'm not interested in reverse iteration. The application will be multithreaded, hence the weird requirement.
You can call List#listIterator(int index) with index = size() -1 to get an iterator to the current last element of the list. See documentation: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/List.html
However, you are going to be stuck from there.
Whether the List implementation you are using isn't thread-safe, which is the case for LinkedList, ArrayList and most others, and any attempt to use the iterator after the list has been structurally modified is going to result in a ConcurrentModificationException being thrown.
A list is structurally modified when its size changes, i.e. on additions and removals.
Or the List implementation you are using is thread-safe, in which case you have no guaranty that the iterator will have access to the elements added to the list after the creation of the iterator.
For example, it wouldn't be the case with CopyOnWriteArrayList, for which the iterator iterates through data as it was at creation (like a snapshot).
You must find an implementation of List that clearly describe this behavior and explicitly say it in its documentation. As far as I know, there doesn't exist any that allow it, at least in the standard library.
Stack<String> ST = new Stack<String>();
ST.add("one");
ST.add("two");
ST.add("three");
ST.add("four");
ST.addAll(ST.subList(0,2));
System.out.println(ST);
Following Simple Code give java.util.ConcurrentModificationException.I not able to figure it out what is the reason behind for this exception?
List.subList returns a view into the container, not a copy.
From the documentation
The semantics of the list returned by this method become undefined if
the backing list (i.e., this list) is structurally modified in any way
other than via the returned list. (Structural modifications are those
that change the size of this list, or otherwise perturb it in such a
fashion that iterations in progress may yield incorrect results.)
So when you call addAll, it modifies the underlying container and changes its size, invalidating the sublist. But it's still trying to iterate over the sublist to continue adding things.
The documentation for the subList method says:
The semantics of the List returned by this method become undefined if the backing list (i.e., this List) is structurally modified in any way other than via the returned List. (Structural modifications are those that change the size of the List, or otherwise perturb it in such a fashion that iterations in progress may yield incorrect results.)
In other words, you're not allowed to change the real list while you're accessing the sublist.
When you call
ST.addAll(ST.subList(0,2));
you're causing addAll to traverse the sublist and modify the real list (ST) at the same time. addAll will take the first element from the sublist and append it to ST, which is a structural modification that invalidates any sublists based on ST. Then addAll will try to take the second element from the sublist, but the sublist is now invalid because of the change that was just made to ST, so it throws the exception.
The problem happens in here:
ST.addAll(ST.subList(0,2));
The problem is that under the hood the following things are happening:
The ST.subList(0,2) call creates a wrapper for the original list.
The ST.addAll call creates an Iterator for the sublist which is actually a wrapper for a ListIterator for the original list.
Then, while iterating the sublist (and hence the list), it pushes the elements it finds back onto the original list.
The last is a concurrent modification.
Note that this is inherent, not just an implementation detail. The subList method returns a view of the original List. Therefore your statement is inherently iterating and modifying the same (underlying) list concurrently.
Is there an efficient method to remove a range - say the tail - of X elements from a List, e.g. LinkedList in Java?
It is obviously possible to remove the last elements one by one, which should result in O(X) level performance. At least for LinkedList instances it should be possible to have O(1) performance (by setting the references around the first element to be removed and setting the head/tail references). Unfortunately I don't see any method within List or LinkedList to remove the last elements all at once.
Currently I am thinking of replacing the list by using List.subList() but I'm not sure if that has equal performance. At least it would be more clear within the code, on the other hand I would loose the additional functionality that LinkedList provides.
I'm mainly using the List as a stack, for which LinkedList seems to be the best option, at least regarding semantics.
subList(list.size() - N, list.size()).clear() is the recommended way to remove the last N elements. Indeed, the Javadoc for subList specifically recommends this idiom:
This method eliminates the need for explicit range operations (of the sort that commonly exist for arrays). Any operation that expects a list can be used as a range operation by passing a subList view instead of a whole list. For example, the following idiom removes a range of elements from a list:
list.subList(from, to).clear();
Indeed, I suspect that this idiom might be more efficient (albeit by a constant factor) than calling removeLast() N times, just because once it finds the Nth-to-last node, it only needs to update a constant number of pointers in the linked list, rather than updating the pointers of each of the last N nodes one at a time.
Be aware that subList() returns a view of the original list, meaning:
Any modification done to the view will be reflected in the original list
The returned list is not a LinkedList - it's an inner implementation of List that's not serializable
Anyway, using either removeFirst() or removeLast() should be efficient enough, because popping the first or last element of a linked list in Java is an O(1) operation - internally, LinkedList holds pointers to both ends of the list and removing either one is as simple as moving a pointer one position.
For removing m elements at once, you're stuck with O(m) performance with a LinkedList, although strangely enough an ArrayList might be a better option, because removing elements at the end of an ArrayList is as simple as moving an index pointer (denoting the end of the array) one position to its left, and no garbage nodes are left dangling as is the case with a LinkedList. The best choice? try both approaches, profile them and let the numbers speak for themselves.
I am not clear on a point in the documentation of List.
It says:
i) Note that these operations may execute in time proportional to the
index value for some implementations (the LinkedList class, for
example).
ii) Thus, iterating over the elements in a list is typically
preferable to indexing through it if the caller does not know the
implementation.
Note that I put the (i) and (ii) in the quote.
Point (i) is pretty obvious due to the way we access a linked list vs the random access of an array.
I can not understand point (ii) though.
What do we gain by prefering an iterator if we don't know the implementation?
I mean if the implementation is a LinkedList is there any difference in the performance than accessing via the index?
I imagine not, since the Iterator would be manipulating a LinkedList anyway.
So there would be no difference.
So what is the meaning of the recommendation of (ii) in the doc?
The iterator of a linked list can just have a pointer to the next node in the list, and go to the next node each time next() is called. It doesn't start from the beginning every time. Whereas if you use an index and call get(i), the linked list has to iterate from the beginning until the ith element at each iteration.
What you missed is that the iterator implementation of an ArrayList and the one of a LinkedList are completely different.
No, if the implementation is a LinkedList then an iterator will be much more efficient - O(n) for iterating over the whole list instead of O(N2). As the iterator is provided by the list, it has access to the internal data structures. It can just keep a reference to "the current node" making it a constant time operation to get to the next one: just follow the link!
(If you're still confused, I suggest you just look at the implementation - that's likely to make it clearer.)
I want to implement a blocking where I can add element any time, any way. But I must be able to access them sequentially.
For example, consider a queue of x elements where the elements 1,4,8,10 have been added. So 10 can be accessed, but until 9 is added and accessed, 8 cant be. In short, all the elements are interrelated.
Please let me know if java already has such type of collection implemented. So I can use it directly.
You're talking about either a stack or a queue, depending on if you want them to be FIFO or LIFO, combined with inserting the elements in numerical order in the first place - meaning you're sorting the elements upon insertion so they are always in the correct numerical order.
By sorting the elements by numerical order upon sort, it's guaranteed that they'll be in the order you expect when you remove them.
You can use Java's a LinkedList to both insert elements where you want them in the list, and also remove them either form the "back" or "front" of the list, as needed.
Finally, in order to ensure that you cannot remove an item unless it is the next in the sequence, you need to simply do a check on the value before removing it from the list to make sure that it was sequentially the next one after the last element removed. If it doesn't pass that criteria, either return "false" or some other value that indicates that nothing can be removed from the list at this time.
Also, check out this question: Creating a blocking Queue<T> in .NET? - it's not Java, but it's very similar, and may provide some insight.
Wrap Queue with logic that pushes items to it in order. Eg. create a class which implements Queue and BlockingQueue. Most methods (like get) delegates directly to something like an internal ArrayBlockingQueue, but "put" would put stuff onto the internal ArrayBlockingQueue in order. If put is called with an element that should not yet be accessible, you store it in another, intermediate, data structure.
Every time put is called with an element that is "next up", you push it to the queue, and then go through your intermediate data structure and add any elements to the queue that can now be added.