How to get Node-Entry Reference from LinkedList in java - java

How to get the reference to the actual Node (entry) object from LinkedList - Not the value that it holds?
Something like this :
import java.util.LinkedList;
public class Main {
public static void main(String[] args) {
LinkedList<String> test = new LinkedList<String>();
test.addLast("first");
test.addLast("second");
test.addLast("third");
var thirdNodeReference = test.getLastNode(); // Does this even exist ?
test.addLast("fourth");
var secondNodeReference = thirdNodeReference.previous(); // To perform such operations.
}
}
Does there exist a method like LinkedList.getLastNode() in java LinkedList so that one can perform previous() or next() operations on it?
I know LinkedList.listIterator() exists but that's not useful, because I'll be having references to each Node (entry), and I need to work with them - such as lastNodeReference in the code above.
If such a functionality doesn't exist in JAVA Standard Library, is there any 3rd party (external) Library that I can use?
Reason:
I need to access the Node to perform remove() operation in O(1).
In the actual JAVA code implementation it performs this in O(N) by traversing the list to find the Node containing the given object by performing equals() on every node on it's way. Also, check this comment.
This can be performed ideally in O(1) if we have a direct reference to Node object - because remove() only requires a change of 2 pointers of previous and next Node.

There is a descendingIterator method on LinkedList, which is described as Returns an iterator over the elements in this deque in reverse sequential order, while it isn't (completely) clear what OP wants, Iterator does have a .next, .previous, and .remove methods.

a linked list can be represented as such:
so no, you can't get the previous element with a linked list.
You might want to implement a double linked list tho ( exemples codes can be found quite easily on google)

Related

Java Collection (LinkedList Concepts)

When I declare LinkedList like:
List<String> names = new LinkedList<String>();
it does not support any of the LinkedList's special methods (ex: names.peekLast(), names.pollFirst() )
But when I declare like:
LinkedList<String> names = new LinkedList<String>();
then it supports these methods.
Yes, it is obvious that reason is the reference, as LinkedList contains that's methods and List does not have!
But my question is that when I want to work with LinkedList, which one is better and correct? Or what is the usage of them?
If you need to use LinkedList methods that don't exist in List, you should use a LinkedList reference (you could use a List reference and cast to LinkedList in order to call LinkedList specific methods, but that would make less sense).
Otherwise, it is preferable to use the List interface for holding the reference, since it makes your code more generic, since it won't depend on any specific List implementation.
Well, List is basically backed by an array which is usually bigger than the current number of items. The elements are put in an array, and a new array is created when the old one runs out of space. This is fast for access by index, but slow at removing or inserting elements within the list or at the start. Adding/removing entries at the end of the list is reasonably cheap.
LinkedList is a doubly-linked list - each node knows its previous entry and its next one. This is fast for inserting after/before a particular node (or the head/tail), but slow at access by index.
LinkedList will usually take more memory than List because it needs space for all those next/previous references - and the data will probably have less locality of reference, as each node is a separate object. On the other hand, a List can have a backing array which is much larger than its current needs.
Reference from Difference between List<T> and LinkedList<T>
You can also refer to oracle docs
Linked List
All of the operations perform as could be expected for a doubly-linked list. Operations that index into the list will traverse the list from the beginning or the end, whichever is closer to the specified index.
List
The List interface provides four methods for positional (indexed) access to list elements. Lists (like Java arrays) are zero based. Note that these operations may execute in time proportional to the index value for some implementations (the LinkedList class, for example). Thus, iterating over the elements in a list is typically preferable to indexing through it if the caller does not know the implementation.
Well there is very simple explanation regarding that is List<> is like array which is making new array when its running out of space. And LinkedList<> is like doubly-linked list where each an every node will have link of previous node as well as next node.
More of that you can search from oracle docs
https://docs.oracle.com/javase/7/docs/api/java/util/List.html
and
https://docs.oracle.com/javase/7/docs/api/java/util/LinkedList.html
You can differentiate by your self. :)

expose the next/prev pointer in a generic list

I want to have a generic doubly linked list where, when I create a List (where point has getX() & getY()), it now also has getPrev() and getNext() where prev/next are the previous/next object in the list.
This is a piece of cake to do if I write my own list code (which I do not want to do). Is there a way to do this with generics or some other library? Basically, rather than have an invisible container object that points to my point as well as a prev/next pointer, can I push that prev/next pointer to my object?
thanks - dave
java.util.LinkedList<E> is already a doubly-linked list. LinkedList.listIterator(int) returns a ListIterator<E> object, which exposes the methods next() and previous(), among other things.
I don't think that you can with java.util.LinkedList
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/LinkedList.java#LinkedList
Have a look at line 95. The class only keeps track to the head of the list so each call to getNext and getPrev will always run in O(N) time never O(1)
You can't use LinkedList (in either a is a or has relationship) to implement getNext and getPrev methods and have those methods run in constant time. As the entity class is private in LinkedList and so is the pointer to the head of the list. You can do it in O(n) like this getNext(get(cursor++)); as get takes O(n) time. There are ways you could do it (refletion) but you are better off to just write your own implementation of a linked list or live with the ListIterator.

Edge reversing on directed graph

I have a directed graph implemented with the adjacency lists using a Java HashMap. Graph class stores only a pointer like this:
HashMap<Node<V>, List<Edge<V>>> graph;
I'm trying to write a method that can perform a transposition of the graph (by side effect). Here is the code:
/**
* Helper method for connection test
*/
public void reverseDirection(){
for(Node<V> v : getNodes()){
for(Edge<V> e : getOutEdges(v)){
Node<V> target = e.getTarget();
int weight = e.getWeight();
graph.get(v).remove(e);
graph.get(target).add(new Edge<V>(v, weight));
}
}
}
While executing some tests i get this:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.LinkedList$ListItr.checkForComodification(LinkedList.java:953)
at java.util.LinkedList$ListItr.next(LinkedList.java:886)
at esercitazione9.Graph.reverseDirection(Graph.java:71)
at esercitazione9.GraphUtil.fortementeConnesso(GraphUtil.java:126)
at esercitazione9.GraphUtil.main(GraphUtil.java:194)
Javadoc says that this exception does not always indicates that an object has been concurrently modified. It may occurs even when a thread modifies a collection directly while it is iterating over the collection.
This is exactly my case, but I have no ideas to solve it. There is another way to reverse all the edges directions without having iterator-collection interference? Note: computational cost can't be above O(n+m).
You cannot remove item from the collection you iterate over in any other way than using the iterator's remove() method (well, unless it's ConcurrentHashMap, I cannot think other exceptios at the moment). There are two canonical solutions to this problem:
Rewrite your loops to use explicit Iterators and call remove instead of graph.get(v).remove(e);
Create a separate collection to hold items to remove (or, alternatively, items to retain) from the collection you iterate over, and do it after the actual iteration.
As you explicitly ask for "not 1", I believe it is the only option. Computational cost should not increase if you store items to remove, as the number of allocations and insertions cannot be larger than O(n+m) (n collections, m removed edges total). Keep in mind that in case your graph contains loops, special care must be taken.
Ok. I just modified the code as suggested:
public void reverseDirection(){
Collection<Edge<V>> removed = new LinkedList<Edge<V>>();
for(Node<V> v : getNodes()){
for(Edge<V> e : getOutEdges(v)){
Node<V> target = e.getTarget();
int weight = e.getWeight();
removed.add(e);
graph.get(target).add(new Edge<V>(v, weight));
}
graph.get(v).removeAll(removed);
}
}
I think now there are some issues with the logic of the algorithm because doesn't return the expected result. I will post the fixed code later.

Are there any performance differences between singly- and doubly-linked lists?

Our homework assignment asks us to prove that the Java LinkedList implementation is doubly-linked and not singly-linked. However, list operations such as adding elements, removing elements, and looking elements up seem to have the same complexity for both implementations, so there doesn't seem to be a way to use a performance argument to demonstrate the doubly-linked nature of Java's LinkedList. Anyone know of a better way to illustrate the difference between the two?
Look at iterating in forward or backward direction, removing the "before-last" element, and such.
It's quite an easy proof -- you look at the source code and see that each node has a .previous pointer :)
http://www.docjar.com/html/api/java/util/LinkedList.java.html
Consider the following nodes, single and double.
class SingleLinkedNode {
E data;
SingleLinkedNode next;
}
class DoubleLinkedNode {
E data;
DoubleLinkedNode prev;
DoubleLinkedNode next;
}
If we want to remove from a DoubleLinkedList (assuming we have already FOUND the node, which is very different) what do we need to do?
Make the node before the deleted
one point to the one after.
Make the node after the deleted one point to the one before.
If we want to remove from a SingleLinkedList (assuming we have already FOUND the node, which is very different) what do we need to do?
Make the node before the deleted one point to the one after.
You'd think that means it's even faster in a single linked list than a double.
But, how are we doing to delete the node if we don't have a reference to the one before it? We only have a reference to the next. Wouldn't we have to do a whole other search on the list just to find prev? :-O
The Java List interface doesn't have a method which allows you to remove an item without searching through a linked list. It has remove(int index), which would have to scan the list to find the indexed entry, and it also has remove(Object o), which has to scan the list as well. Since a linked list implementation can save the necessary previous-item entry context while scanning, remove has equivalent complexity for singly- and doubly-linked lists. This state can be saved in an iterator, as well, so Iterator.remove() doesn't change this. So I don't think you can tell from remove performance.
My guess is that the "right" answer to this is to create several lists of different sizes and time the performance of .indexOf() and .lastIndexOf() when searching for the first or last object. Presuming that the implementation is doubly-linked and searches from the beginning of the list for .indexOf() and searches from the end for .lastIndexOf(), the performance will be length-dependent or length-independent.

How to pop items from a collection in Java?

Is there a method in JDK or apache commons to "pop" a list of elements from a java.util.List? I mean, remove the list of elements and return it, like this method:
public Collection pop(Collection elementsToPop, Collection elements) {
Collection popped = new ArrayList();
for (Object object : elementsToPop) {
if (elements.contains(object)) {
elements.remove(object);
popped.add(object);
}
}
return popped;
}
If you're looking for a stack-like structure I suggest accepting a Deque (LinkedList is the most common implementation) instead of a Collection.
If you don't actually need to treat it as a stack, just get an iterator from the Collection and use the remove() method:
for (Iterator<SomeType> it = elements.iterator(); it.hasNext(); ) {
SomeType e = it.next();
it.remove();
popped.add(e);
}
Do note that remove is an optional operation, and some implementations may throw an UnsupportedOperationException (for example, the iterator returned by a Collection from Collections.unmodifiable...() will).
Edit: After looking more closely at your question, I think you just need this:
elements.removeAll(elementsToRemove);
If your main point is you need to know exactly which elements were actually popped, I think you're stuck with your original code.
There is no such method in the standard JDK-provided methods. Apache Commons provides the ListUtils.subtract() method.
Edit: As other answerers have noted, your use of the term pop is nonstandard. Usually,
The pop operation removes an item from the top of [a stack]
Wikipedia has a nice description of stacks.
I guess no, because you definition of 'pop' operation is highly non-standard. Usually it takes no arguments (except collection itself) and returns and removes the top-most one.
But once you noted apache commons, this would achieve the same effect as your code.
Collection result = CollectionUtils.intersection(a, b);
a.removeAll(b);
edit
http://commons.apache.org/collections/api-release/index.html
Linked List provides the functionality as you require, provides a push and pop method.
Refer to the documentation as provided:
There isn't a method exactly like what you are asking for, but it looks like you are already pretty close with your code.
Some suggestions:
Consider using removeAll(object) instead of remove(object) if elements is an arbitrary collection since you may need to remove duplicates e.g. if elements is a list.
contains() is slow for some collection types (e.g. lists) since it needs to traverse the entire data structure. Given that this is in your inner loop you are at risk of O(n^2) performance issues. If you can make the algorithm work with a HashSet or HashMap then contains() will by O(1) and your algorithm will be much more efficient.

Categories