I very well understand the concept of SLL or DLL.
But which one of them are we using in Collection interface?
So far I have encountered LinkedList in interfaces List,Queue and Dequeue.
Is there any other? And what type of LinkedList are we using in these 3 interfaces?
How can I even know it?
List, Queue and Dequeue are just interfaces which provide a contract to be satisfied by the implementation. It doesn't matter how the list is implemented (in fact it doesn't even have to be a list).
The first line of LinkedList javadoc states
Doubly-linked list implementation of the List and Deque interfaces.
All linked lists in java are doubly linked lists
Arrays and array lists have a major disadvantage: Deleting an element from the middle of the array costs too much. Because all elements in the array after the deleted element must be moved to the front of the array. (The same goes for inserting an element into the array)
And then Java deliver the solution:
Java introduced a linked list to solve the problem. In the Java programming language, all linked lists are actually two-way linked, in which each node also stores a reference to the predecessor node.
Related
This question already has answers here:
When to use LinkedList over ArrayList in Java?
(33 answers)
Closed 10 months ago.
I really don't see how linked lists are better than array , the insertion and deletion complexities are same , eg. , In array the insertion at rear is O(1) while for linked lists the insertion at head is O(1) , and simillarly insertion in arrays at front is O(n) but for the later it is O(n) to insert at the rear end.
Apart from the only fact that linked lists are dynamic in nature ,I dont see any benefits of linked lists over arrays. Moreover , I can use a dynamic array to counter that problem.
Again Array also have better results when we want to access an element.
So can anybody please tell me why are linked lists better than array? And if they are not better , then why do we use it?
No data structure is universally better than another data structure. There are benefits and drawbacks and which is better depends on what benefits and drawbacks are more important for your use case.
the insertion and deletion complexities are same
Firstly, it isn't possible to insert or delete elements of arrays at all. Their size remains constant. But I'll assume that you meant "dynamic array" data structure i.e. std::vector and java.util.ArrayList (not to be confused with dynamically allocated array which is also called "dynamic array").
The insertion and deletion complexities between linked lists and dynamic array are not the same.
but for the later it is O(n) to insert at the rear end.
Given a an iterator to a linked linked list, you can insert after the pointed element in constant time. Hence, if you maintain an iterator to the end of the list, you can insert there in constant time.
An important advantage of linked list over the dynamic array, besides the complexity, is that the elements remain stable in memory. In vector, if adding an element exceeds the capacity, then all iterators and references to existing elements are invalidated. Iterators as well as references to linked list elements remain valid until the element is erased. If you need this property, then using a dynamic array is not an option.
Linked lists, as independent data structures, are rarely used.
Quite often, however, objects are linked into a list by incorporating next and maybe prev pointers directly into the objects themselves. As a data structure, that is often referred to as an "intrusive" linked list.
Sometimes this is used to add features to existing data structures. In Java you can see this in LinkedHashMap, which links the map entries together into a list, preserving their insertion or access order and allowing you to use it as an LRU cache. Similarly, leaf nodes in a B+tree are often linked onto a list to simplify traversal. There are many examples.
If we are implementing a LRU cache using HashMap and DoublyLinkedList, What is the best way to implement evict() method with O(1) time complexity?
LinkedList from Java didn't expose the Node type (which is a private static inner class).
So you can't remove it in in O(1), because a sequential scan is required.
To get O(1), you need to be able to access the Node type, so that could remove it without scan.
You have to write it by yourself. Fortunately, a doubly linked list is relatively easy to write, and it's a pretty beneficial & fun task to do.
How to remove with a given Node?
Refer to this answer: https://stackoverflow.com/a/54593530
The method LinkedList.java -> removeNode() remove a given node, without sequential scan.
The code in this answer is for a singly linked list, the remove for a doubly linked list is even simpler in some case.
Tips:
If the given node is the end node in linked list, then you need the previous node too.
But that's for singly linked list, for a doubly linked node, the node itself contains the previous node, so you don't have to pass previous node to the removeNode() method.
BTW
Why it's beneficial?
linked list is the most basic structure (except array and bits), that some other very basic structures could built base on.
e.g both queue and stack could be implemented easily with a linked list.
Concurrent access
java.util.LinkedList is not thread-safe, your LRU might needs some concurrent control, but I'm not sure.
If need, then java.util.concurrent.ConcurrentLinkedDeque is a good example to refer to.
#Update LinkedHashMap
java.util.LinkedHashMap, is a combination of hashtable & doubly linked list.
Mechanism:
It extends HashMap to get the O(1) complexity for the common operations.
And use doubly linked list to keep track of insertion order.
head is the eldest item, and tail is the newest item.
It can be used to impl some kind of cache, though I am not sure will it be fully qualified for your requirement.
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.
I was wondering which Java collection types are traversed fastest. Collections I am most interested in are...
array
LinkedList
Queue
PriorityLinkedList
HashMap
Actually among concrete classes of Collection interface , traversing will be fast through array. Its because as you know it traverse with the index of the element.Since it follows the index pattern so,traversing through index it makes our traversing fast. Why not others? Let me explain one by one..
1.LinkedList : LinkedList follows the insertion order.If you traverse the data and searching for elements,for every element it will search from beginning. So traversing becomes slow.
2.Queue : LinkedList and PriorityQueue are two concrete classes of Queue. The elements of the priority queue are ordered according to their natural ordering, or by a Comparator provided at queue construction time, depending on which constructor is used.It's not guaranteed to traverse the elements of the priority queue in any particular order.If you need ordered traversal, consider using Arrays.sort(pq.toArray()). So it becomes useless for traversing provided if you traverse without sorting it explicitly.
3.HashMap: If you use Map instead of Collection , traversing is not guaranteed here because it works on hashcode of the key element. So here again traversing becomes useless. You can directly search the element by providing key-value of the element.
4.PriorityLinkedList: This class does not exist in Java APIs.
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.