Java LinkedList class - java

In class, I've implemented my own LinkedList class with a private Node class so I've never run into this issue before. But now I'm trying to re-do a problem using Java's built-in LinkedList library and am running into trouble. (its also been a few years since I last used Java).
Lets say I had this simple skeleton. How would I pass the head Node into the function?
public static void main(String[] args)
{
LinkedList<Integer> test = new LinkedList<Integer>();
doSomething(test.get(0));
}
private static void doSomething(Node a)
{
//stuff
}
Also could someone remind me what the difference is between these two? I know the first you're basically casting the list as a LinkedList but why do so?
List<E> test = new LinkedList<E>();
LinkedList<E> test = new LinkedList<E>();

Looking at the documentation for LinkedList, there are no methods that expose the nodes of the list. In fact, LinkedList might even be implemented in a completely different way and not use nodes at all and still have all the properties and performance guarantees of a linked list. It's an implementation detail.

The standard library LinkedList class uses encapsulation to avoid exposing implementation details (like how list nodes are implemented) to the user of the class (you).
There is no way you can get a reference to the internal list node, save for using advanced techniques like reflection that break encapsulation.
Instead of playing around with list nodes and pointers between them, you use the methods the LinkedList class provides to add and retrieve the list elements. For example:
LinkedList<Integer> test = new LinkedList<Integer>();
test.add(314);
test.add(879);
Integer first = test.getFirst(); // returns 314
Integer first = test.get(1); // returns 879
The benefit from encapsulation is that JVM implementors are free to change the internal implementation of LinkedList completely without fear of breaking your program.
You get the same benefit in your own program if you use the List interface instead LinkedList class by writing:
List<E> test = new LinkedList<E>();
If you do this, you are free to change test from LinkedList to ArrayList or any other list implementation at a later point with no other changes to the code, for example if the application requirements change or if you find that ArrayList gives you better performance.

Java's native linked class has some issues. Iterators can be used to access nodes, but are limited as noted below. There is no way to move nodes within a list or from list to list, such as C++ std::list::splice.
https://en.cppreference.com/w/cpp/container/list/splice
For Java, "moving" nodes requires removing and inserting nodes, which involves deallocation for any node removed, and allocation for any node inserted.
Java's iterators can't be shallow copied. An assignment just sets another variable to point to the same iterator object. (C++ iterators don't have this issue).
Any removal or insertion of nodes from a list will invalidate all iterators to that list (except for the iterator used to do the remove or insert). (C++ iterators function as expected).

Related

General use of Linked List

I know you can create your own Linked List class or import one with java.util.
Like so :
import java.util.*;
LinkedList<String> ll=new LinkedList<String>();
and then do some stuff to the list with the already existing methods, like add, get, set...
But you can also create your own Linked List liked that :
class LinkedList {
Node head; // head of list
class Node {
int data;
Node next;
Node(int d) { data = d; }
}
}
But if you're doing it like that you need to create all of the methods.
My question is pretty simple, should I use method 1 or 2 ? And if both are fine when would it be better to use one over another.
If you need a general-purpose List, use java.util.LinkedList. It's a standard class, mature, well-tested, well-understood by almost any Java dev... and, ofc, it's concise, because you don't have to implement it.
Actually, don't use it: use java.util.ArrayList or java.util.ArrayDeque, they out-perform LinkedList in almost all circumstances. See When to use LinkedList over ArrayList in Java?
If you really need something more specialized, implement your own, but only if you really, really need it.
Only make your class implement java.util.List if you actually need it to.
A good starting point to avoid having to implement "everything" in the interface is to extend java.util.AbstractList: this only requires you to provide an implementation of get(int), size() and, if you want the list to be modifiable, set(int, E) (you may well want to override others to get better performance for a linked list).
Don't reinvent the wheel unless you need something extremely specific that the existing wheel doesn't provide.
Also, might be worth mentioning that linked lists have poor performance characteristics since the memory they occupy isn't continuous, causing the multiple reads from main memory (link).

Putting two linkedlists together without copying - Java, Using standard API [duplicate]

This question already has answers here:
Merge two lists in constant time in Java
(4 answers)
Closed 9 years ago.
I have two LinkedList in my code and I need to make one that have both. I will not need this Lists anymore, just the new one, which have all data I need.
I could use .addAll(), but performance is I huge issue and I cant wait to copy,adding references, everything every time..
I am looking for something like we normally do if we create our own linkedlist, just connect the last node from one to the fist from the second.. Is there a way to do that using the LinkedList class from the java api?
Merging collections is a different case, although the operation means almost the same, my issue is just regarding performance and just for linkedlists, which normally can do what I need. Also "merging" is kind of an ambiguous term, what I want is just to put then together no matter what order they are, with performance in mind.I am not looking if is possible to merge...
Another thing, my question is just regarding the API, I am not looking for building my own code (boss requirement) and that is why is different from this one: Merge two lists in constant time in Java - not useful answers there either..
If you are using LinkedList then you are most likely not interested in indexed access (since indexed access is slow... but keep in mind that a list only stores references, so for very large lists with few insert/removes you are going to be more memory efficient with an ArrayList as it doesn't need to allocate each node on the heap)
So what you actually want is something that gives you most of the List contract... or maybe not even that.
It could well be that all you want is something that gives you Iterable<String>... if that is the case then you have a very easy life:
public class UberIterable<T> implements Iterable<T> {
private final List<List<T>> lists;
public UberIterable(List<T>... lists) {
this.lists = Arrays.asList(lists);
}
public Iterator<T> iterator() {
return new Iterator<T>() {
Iterator<List<T>> metaNext = lists.iterator();
Iterator<T> next;
public boolean hasNext() {
while (true) {
if (next != null && next.hasNext()) return true;
if (metaNext.hasNext()) next = metaNext.next(); else return false;
}
}
public T next() {
if (!hasNext()) throw new NoSuchElementException();
return next.next();
}
public void remove() {
throw new UnsupportedOperation();
}
}
}
}
That is a basic implementation that will give you a merged view of many lists. If you want to get more of the contract of List you could repeat the same tricks only with a better implementation of ListIterator which will get a lot of what you are probably after, or finally by extending AbstractList and overriding the appropriate methods with your new ListIterator implementation
If you only want to iterate over the new list and you can replace List with Iterable you can use Guava's Iterable.concat as described here:
Combine multiple Collections into a single logical Collection?
I'm afraid the answer is no. The internal Entry class used by LinkedList is private, and all the public methods exposed by LinkedList work with general collections.
Your use case seems reasonable to me, but this implementation doesn't support it.
I'm afraid that the only way to do this is by using reflections... When you take a look at the source code of LinkedList, you can see that the subclass Entry<E> is private, which is a problem if you want to connect the first and last entries to other entries, in order to merge the list.
Update: Even reflections are not safe (unless you add checks), because Oracle changed the name of the subclass Entry to Node and changed the order of arguments of the constructor! in JDK 7, which is stupid IMHO.
Dirty solution: Do a whole copy paste of the source code and change the private keywords to public. However, I'm not sure this is allowed by Oracle. Check their license.
One way you could go about doing this is by using getLast() to grab the last element off the one of the lists and then use addFirst() on the other in order to add it to the front.
As has been said here, however, addAll() would not be copying anything and could be used just as easily.
If your issue is with the actual instantiation of node objects in the LinkedList, you may need to implement your own version that exposes more of the implementation mechanisms in its API.
why not create a wrapper/proxy class that implements List and contains references to the 2 sublists, then implement the List methods (or at least the ones you need downstream) - a little bit of work but if copying either of the lists is really the issue sounds like it is worth it.
import java.util.LinkedList;
public class MergeLinkedList {
public static void main(String[] args) {
LinkedList<String> mainlist = new LinkedList<String>() ;
mainlist.add("A");
mainlist.add("B");
LinkedList<String> secondlist = new LinkedList<String>() ;
secondlist.add("C");
secondlist.add("D");
mainlist.addAll(secondlist);
System.out.println(mainlist);
}
}
O/P
[A, B, C, D]
you have to use addall();

Java LinkedList methods for Queue and Stack

if you look at the LinkedList methods of Java, it does offer operations for Queue, Stack, Deque.
And I am aware that you can implement Queue, Stack or Deque with a LinkedList. If you look at C# implementation though, Queue and Stack uses arrays.
My Curiosity is, why they offer a push(T e) method for a linked list?
Why Queue and Stack are not separate classes, just like C#.
Below is the code for push and pop which is duhhh. But why?
public void push(Object obj)
{
addFirst(obj);
}
public Object pop()
{
return removeFirst();
}
If you look at HashMap, or HashSet, it uses array internally, and there is LinkedHashSet and map correspondingly to keep ordering.
This is not really confusing, but it doesnt make sense really.
Why java has such implementation?
Focus on data structure implementation:
Linked list is efficient for frequent add and remove. (as Queue and Stack usually do, and iteration operation is rare). Array is not, it needs array-copy operation which is time consuming.
A double-linked list such as Java's LinkedList is a rather flexible data structure, so it makes sense to implement several data structures using it as a base. So if you want to view it as a Queue, you'd say something like this (I'm omitting type parameters):
Queue q = new LinkedList();
If you want to use it as a stack, you would declare it like this:
Deque s = new LinkedList();
And so on. It all boils down to code reutilization, after all, why implement several different classes for similar functionality, when a single class (LinkedList in this case) suffices?
Basic OOD: while perhaps a fuzzy line, Queue, Stack, and Deque roughly describe operations you can perform on a collection and hence deserve to be interfaces. LinkedList describes the implementation and performance characteristics of an interface and hence deserves to be a class. That implementation could be (is) exposed as multiple interfaces. To me, the real question is, "Why is Stack a class?"
LinkedList implements Queue interface because you might want to use the linked list as a Queue in some places. What this means is that a method which takes a queue as input param can also process linked lists. The following works
List<String> linkedList = new LinkedList<String>();
linkedList.add("element1");
linkedList.add("element2");
Queue<String> q = (Queue<String>)linkedList;
q.poll(); //removes and returns element1 from the linkedList
Java has a separate class called java.util.Stack which extends from vector which in turn is a array based implementation. But this is a thread safe version. If you don't worry about thread safety, then you can use ArrayDeque as a stack.
Queue is an interface, and has other implementations besides LinkedList. There's also a Stack class.
Ultimately, it just seems like an arbitrary decision, and the underlying implementation doesn't really matter that much (IMO).

Transforming a LinkedHashSet into a List

Let's say the List b is a LinkedList.
Let's say the List a is also a LinkedList.
Question:
How do I append these list in constant time?
It is possible, because LinkedList is presumably a doubly linked list (otherwise it couldn't implement the Deque interface). And appending doubly linked list is a 0(1) operation.
The addAll method doesn't run in constant time.
Question:
How do I transform a LinkedHashSet into a list in constant time?
It is also presumably possible because LinkedHashSet "maintains a doubly-linked list running through all of its entries".
Your assumptions are based on no encapsulation - i.e. that the LinkedHashSet is willing to expose its internal LinkedList to the outside world, when I suspect it isn't.
Likewise joining two linked lists - I don't know offhand whether each node knows which list it's in, but that's certainly a possibility which would scupper your constant-time appending. Even if they don't, as soon as you attach the head of one list to the tail of the other, you end up with problems - you've got two lists both referring to the same data, which would have some odd consequences.
In other words, both of these operations are feasible in a computer science sense, and you could build your own implementations to support them, but that doesn't mean the Java API exposes its internals in a way which enables those operations.
You would need to implement your own classes. The LinkedList class does not expose its internal node structure, so you can't just point its last node to the first node of another LinkedList.
The answer is similar for the LinkedHashSet: While it does maintain this doubly-linked list, you don't get to access it.
You do not get access to it but I suspect that Collections does, so you should not give up hope that this is a viable and quick solution to your problem.
I looked further and you are right. If you have Set<Whatever> whatever = SOME CONSTRUCTOR then you can code List<Whatever> list = new LinkedList(whatever); because a LinkedList has a Collections constructor and Set has a Collections interface.

Java data structures (simple question)

Say I want to work with a linked list in java. I thought that the best way to create one is by:
List list = new LinkedList();
But I noticed that this way I can only use methods on the list that are generic. I assume that the implementation is different among the different data structures.
So if I want to use the specific methods for linked list, I have to create the list by:
LinkedList list = new LinkedList();
What's the main reason for that?
Tnanks.
List is an interface that abstracts the underlying list implementation. It is also implemented by e.g. ArrayList.
However, if you specifically want a LinkedList, there is nothing wrong with writing LinkedList list. In fact, if you just pass it around as a list, people may (not knowing the implementation) unknowingly write algorithms like:
for(int i = 0; i < list.size(); i++)
{
// list.get(i) or list.set(i, obj)
}
which are linear on a random access list (e.g. ArrayList) but quadratic on a LinkedList (it would be preferable to use a iterator or list iterator). Java provides the RandomAccess marker interface so you can distinguish.
Of course, you can call these methods on a reference of type LinkedList too, but people should be more likely to consider the cost.
As a note, in .NET LinkedList does not implement IList for this reason.
The first idiom allows you to change the runtime type that list points to without modifying any client code that uses it.
What methods in LinkedList do you think you need that aren't in List? You can always cast for those.
But the whole idea behind interfaces is to shield clients from how the interface is implemented.
If you really need a LinkedList, so be it. But I prefer the first idiom, because most of the time I really just need List methods.
Every LinkedList is a List, too. That also means that you can do everything with a LinkedList that you can do with a List and that you can store a LinkedList as List. However, when you store it as List, you can only call methods of the LinkedList that a List also has.
By the way: This is not Generics. Generics are like this:
LinkedList<String> list = new LinkedList<String>();
List list = getSomeList();
Here you're saying that it's a list. You have no idea whether or not it's a LinkedList or an ArrayList or whatever. It is an abstract thing (I assume you mean "abstract" by the word "generic", since generics are a different thing entirely). Thus you can't treat it like it's an LinkedList -- you have to treat it like it's a List (which it is).
The fact that "you know" that it's a LinkedList is all well and good, and you can safely cast if you need to do it. But it might help to tell the compiler that it's a LinkedList, by declaring it as so, if it's always going to act as a LinkedList.

Categories

Resources