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).
Related
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).
what kind of collection should I use if:
I want to store max. 5 Enums in the collection
Reading, writing and iterating over collection can happen multiple
times per second
If I will need to add new element then the oldest
element will be removed (Assume it has e1...e5 and when I add e6 it will be
e2...e6).
I will be almost always iterating over the whole collection. I guess LinkedList is what I need, but I'm not very experienced in Java, so I want to make sure.
LinkedBlockingQueue
LinkedBlockingQueue lbq =new LinkedBlockingQueue(5);
if(!(lbq.offer(newOBject)){
lbq.take();
lbq.offer(newObject);
}
EnumMap might also be useful, keys restricted to enum instances.
What you need here is a Queue Data Structure which supports FIFO .
You can use LinkedList from Collections Framework.It implements Queue Interface.
Read more about Linked List in Java.
If you do not need to enforce the capacity of the queue you can just use LinkedList. It implements Queue interface, which is what you actually need.
Use it like this:
Queue<EnumClass> queue = new LinkedList<EnumClass>();
queue.offer(newObj);
takenObj = queue.poll();
If you have to limit the size an ArrayBlockingQueue would be a good option, since there will be no additional internal object creation (collection backed by an array).
Queue<EnumClass> queue = new ArrayBlockingQueue<EnumClass>(capacity);
Still, using it with Queue interface would be a good idea. That way you can change the actual implementations at will.
Why is Queue an interface, but others like Stack and ArrayList are classes?
I understand that interfaces are made so that clients can implement them and add on their own methods, whereas with classes if every client needs their methods in there it will become huge and bloated..
...or am I missing something here?
A Queue can be implemented in a number of fashions, as can a List or a Set. They all merely specify a contract for different kinds of collections.
An ArrayList, however, is a particular implementation of a List, made to internally use an array for storing elements. LinkedList is also an implementation of a List, which uses a series of interconnected nodes, i.e. a doubly linked list. Similarly, TreeSet and HashMap are particular implementations of sets and maps, respectively.
Now, Stack is a odd case here, particularly because it is a legacy class from older versions of Java. You really shouldn't use a Stack anymore; instead, you should use its modern equivalent, the ArrayDeque. ArrayDeque is an implementation of a Deque (a double-ended queue), that internally uses an array for storage (which is just what Stack does). A Deque supports all of the operations of a Stack, like pop, push, etc. Other implementations of Deque include LinkedList, as mentioned by someone else, although this deviates from Stack in that underlying it is not an array, but a doubly-linked list :-p
Now, there are plenty of implementations of Queue, and many different types of Queues. You not only have BlockingQueues (often used for producer-consumer), whose common implementations include LinkedBlockingQueue and ArrayBlockingQueue, but also TransferQueues, and so on. I digress... you can read more on the collections API in the relevant Java Tutorial.
You get the idea of interfaces correctly. In this case Java standard library already provides both implementations and interfaces.
You are better of using an interface so you can switch the implementation any time.
Hope it makes sense.
I think Stack is well-renowned for being a class that should be an interface. The Java libraries are a bit hit-and-miss when it comes to correctly choosing to provide an interface.
ArrayList is just an implementation of the List interface, so Sun got it correct there! Another classic miss (in my opinion) is the Observable class, which very much needs to be the default implementation of an interface, rather than just a class.
Interesting question. My thought about this that Queue is a basis for a lot of data structures like BlockingQueue, PriorityQueue, Deque, etc. This bunch of classes need specific implementation for various operations so it's much simpler to made Queue as interface.
The reason interfaces are used for List and Queue is NOT to reduce excessive code.
The main advantage of interfaces is they allow you to write flexible, loosely coupled code.
(Here's an awesome answer that describes this concept perfectly)
An interface simply defines a list of methods that will be implemented by a class.
This allows us to do a wonderfully powerful thing:
We can treat all classes that implement an interface the same.
This is a HUGE advantage.
Here's a very simple example:
We want to write a debug method that prints every element in a Collection.
Collection is an interface. It defines a list of operations and does not implement them.
You cannot instantiate a Collection. You can instantiate a class that implements Collection.
There are many classes that implement Collection: ArrayList, Vector, TreeSet, LinkedList, etc... They all have different snazzy features, but they also have certain things in common: Because each class implements Collection, they all implement each method found here.
This allows us to do a very powerful thing:
We can write a method that operates on ANY class that implements Collection.
It would look just like this:
public void printCollection(Collection semeCollection) {
for (Object o : someCollection) {
String s = (o == null) ? "null" : o.toString();
System.out.println(s);
}
}
Because of the magic of interfaces, we can now do the following:
public void testStuff() {
Collection s = new TreeSet();
Collection a = new ArrayList();
Collection v = new Vector();
s.add("I am a set");
a.add("I am an array list");
v.add("I am a vector");
printCollection(s);
printCollection(a);
printCollection(v);
}
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.
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.