I haven't found much information about the time complexity of Collections.rotate(list, k), am I correct in assuming the following?
For ArrayList: O(n) being n the size of the list
For LinkedList and ArrayDeque: O(k)
Thanks in advance.
IMHO the documentation of Collections.rotate() describes the algorithm nicely:
If the specified list is small or implements the RandomAccess interface, this implementation exchanges the first element into the location it should go, and then repeatedly exchanges the displaced element into the location it should go until a displaced element is swapped into the first element. If necessary, the process is repeated on the second and successive elements, until the rotation is complete.
According to this part of the description the time complexity is O(N) for lists that implement the RandomAccess interface (because for such lists the element access is O(1) and the algorithm needs to access N elements), O(N^2) for lists where the element access is O(N) (for example LinkedList) - but only for small N.
If the specified list is large and doesn't implement the RandomAccess interface, this implementation breaks the list into two sublist views around index -distance mod size. Then the reverse(List) method is invoked on each sublist view, and finally it is invoked on the entire list.
This part of the description is for larger lists that do not implement the RandomAccess interface (for example LinkedList). The description mentions 3 calls to Collections.reverse() and the documentation for Collections.reverse() says:
This method runs in linear time.
That means O(N) for each call to Collections.reverse() - but O(3*N) is a constant factor to O(N) which means that the whole operation for Collections.rotate() also runs in O(N).
Note that ArrayDeque does not implement the List interface and you therefore cannot call Collections.rotate() with an ArrayDeque as argument.
Related
I have the following code, where getIDs() returns a list of IDs:
List<Long> ids = getIds();
Long neededID = ids.get(ids.size()-1);
Now sonarqube says:
Collection methods with O(n) performance should be used carefully (java:S2250)
The time complexity of method calls on collections is not always obvious. For instance, for most collections the size() method takes constant time, but the time required to execute ConcurrentLinkedQueue.size() is O(n), i.e. directly proportional to the number of elements in the collection. When the collection is large, this could therefore be an expensive operation.
This rule raises an issue when the following O(n) methods are called outside of constructors on class fields:
I did not find any public link to show you that rule.
So in my understanding the rule says size() has a runtime of O(n) and I could get() an element of the list faster if I would know the last index. So my question is now if there is an way to get the last element of the list faster, without using size().
I have already done some search but the only thing that I found if I search for get last element of list is that you can use list.get(list.size()-1).
list.get(list.size()-1) would always be O(n) because a linked list is not a random access data structure like a primitive array. To retrieve a value of a given position in the list, you would have to traverse the list starting at the first node until you get to the node of the position you want. So, don't use list.get(index) to retrieve the last element. Many implementation maintain a reference to the last node in the list so that retrieving the last element is O(1). I don't have the code of java.util.LinkedList but I would imagine its method getLast() is O(1).
The answer to this question was that a LinkedList.getSize() only has a complexity of O(1). So it was not relevant for me.
I found out that for quite big Arrays (over 1000 entries), the methods A.removeAll(B) is way faster on a HashSet than on an ArrayList.
Do you have an idea of how these methods are implemented and how this could explain that difference?
A set (and thus HashSet as well) contains at most one element of B and since HashSet uses hashes it is quite efficient to locate and remove that element. The overall complexity should thus be O(1) for removing all (that is one) B.
A list can contain any number of B in any location so removing all B has to check all elements. The overall complexity is O(n) since every element has to be checked if it is a B.
Edit:
If B represents a collection/array, i.e. a set of multiple elements, you'd multiply the above complexities by the size m of B, so you'll get O(m) for HashSet and O(n * m) for lists.
Edit 2:
Note that if you have a sorted list the complexity might be reduced to O(log(n)) or O(log(n) * m). For that to work the code removing the actual elements would have to know the list is sorted though and since ArrayList is not guaranteed to be sorted it can't make that optimization.
Basically the reason for both is the time complexity that these specific implementations are trying to achive for theyr respectiv operations.
The time complexity for the ArrayList remove method is O(n - index) source from When to use LinkedList over ArrayList?
While the remove method of the HashSet offers constant time complexity O(1) source from Hashset vs Treeset
I am implementing a public method that needs a data structure that needs to be able to handle insertion at two ends. Since ArrayList.add(0,key) will take O(N) time, I decide to use a LinkedList instead - the add and addFirst methods should both take O(1) time.
However, in order to work with existing API, my method needs to return an ArrayList.
So I have two approaches:
(1) use LinkedList,
do all the addition of N elements where N/2 will be added to the front and N/2 will be added to the end.
Then convert this LinkedList to ArrayList by calling the ArrayList constructor:
return new ArrayList<key>(myLinkedList);
(2) use ArrayList and call ArrayList.add(key) to add N/2 elements to the back and call ArrayList.add(0,key) to add N/2 elements to the front. Return this ArrayList.
Can anyone comment on which option is more optimized in terms of time complexity? I am not sure how Java implements the constructor of ArrayList - which is the key factor that decides which option is better.
thanks.
The first method iterates across the list:
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/ArrayList.html#ArrayList(java.util.Collection)
Constructs a list containing the elements of the specified collection, in the order they are returned by the collection's iterator.
which, you can reasonably infer, uses the iterator interface.
The second method will shift elements every time you add to the front (and resize every once in a while):
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/ArrayList.html#add(int, E)
Inserts the specified element at the specified position in this list. Shifts the element currently at that position (if any) and any subsequent elements to the right (adds one to their indices).
Given the official assumptions regarding the functions, the first method is more efficient.
FYI: you may get more mileage using LinkedList.toArray
I would suggest that you use an ArrayDeque which is faster than a LinkedList to insert elements at two ends and consumes less memory. Then convert it to an ArrayList using method #1.
I am trying to to understand why Java's ArrayDeque is better than Java's LinkedList as they both implement Deque interface.
I hardly see someone using ArrayDeque in their code. If someone sheds more light into how ArrayDeque is implemented, it would be helpful.
If I understand it, I will be more confident using it. I could not clearly understand the JDK implementation as to the way it manages head and tail references.
Linked structures are possibly the worst structure to iterate with a cache miss on each element. On top of it they consume way more memory.
If you need add/remove of the both ends, ArrayDeque is significantly better than a linked list. Random access each element is also O(1) for a cyclic queue.
The only better operation of a linked list is removing the current element during iteration.
I believe that the main performance bottleneck in LinkedList is the fact that whenever you push to any end of the deque, behind the scene the implementation allocates a new linked list node, which essentially involves JVM/OS, and that's expensive. Also, whenever you pop from any end, the internal nodes of LinkedList become eligible for garbage collection and that's more work behind the scene.
Also, since the linked list nodes are allocated here and there, usage of CPU cache won't provide much benefit.
If it might be of interest, I have a proof that adding (appending) an element to ArrayList or ArrayDeque runs in amortized constant time; refer to this.
All the people criticizing a LinkedList, think about every other guy that has been using List in Java probably uses ArrayList and an LinkedList most of the times because they have been before Java 6 and because those are the ones being taught as a start in most books.
But, that doesn't mean, I would blindly take LinkedList's or ArrayDeque's side. If you want to know, take a look at the below benchmark done by Brian (archived).
The test setup considers:
Each test object is a 500 character String. Each String is a different object in memory.
The size of the test array will be varied during the tests.
For each array size/Queue-implementation combination, 100 tests are run and average time-per-test is calculated.
Each tests consists of filling each queue with all objects, then removing them all.
Measure time in terms of milliseconds.
Test Result:
Below 10,000 elements, both LinkedList and ArrayDeque tests averaged at a sub 1 ms level.
As the sets of data get larger, the differences between the ArrayDeque and LinkedList average test time gets larger.
At the test size of 9,900,000 elements, the LinkedList approach took ~165% longer than the ArrayDeque approach.
Graph:
Takeaway:
If your requirement is storing 100 or 200 elements, it wouldn't make
much of a difference using either of the Queues.
However, if you are developing on mobile, you may want to use an
ArrayList or ArrayDeque with a good guess of maximum capacity
that the list may be required to be because of strict memory constraint.
A lot of code exists, written using a LinkedList so tread carefully when deciding to use a ArrayDeque especially because it DOESN'T implement the List interface(I think that's reason big enough). It may be that your codebase talks to the List interface extensively, most probably and you decide to jump in with an ArrayDeque. Using it for internal implementations might be a good idea...
ArrayDeque is new with Java 6, which is why a lot of code (especially projects that try to be compatible with earlier Java versions) don't use it.
It's "better" in some cases because you're not allocating a node for each item to insert; instead all elements are stored in a giant array, which is resized if it gets full.
ArrayDeque and LinkedList are implementing Deque interface but implementation is different.
Key differences:
The ArrayDeque class is the resizable array implementation of the Deque interface and LinkedList class is the list implementation
NULL elements can be added to LinkedList but not in ArrayDeque
ArrayDeque is more efficient than the LinkedList for add and remove operation at both ends and LinkedList implementation is efficient for removing the current element during the iteration
The LinkedList implementation consumes more memory than the ArrayDeque
So if you don't have to support NULL elements && looking for less memory && efficiency of add/remove elements at both ends, ArrayDeque is the best
Refer to documentation for more details.
I don't think ArrayDeque is better than LinkedList. They are different.
ArrayDeque is faster than LinkedList on average. But for adding an element, ArrayDeque takes amortized constant time, and LinkedList takes constant time.
For time-sensitive applications that require all operations to take constant time, only LinkedList should be used.
ArrayDeque's implementation uses arrays and requires resizing, and occasionally, when the array is full and needs to add an element, it will take linear time to resize, resulting the add() method taking linear time. That could be a disaster if the application is very time-sensitive.
A more detailed explanation of Java's implementation of the two data structures is available in the "Algorithms, Part I" course on Coursera offered by Princeton University, taught by Wayne and Sedgewick. The course is free to the public.
The details are explained in the video "Resizing Arrays" in the "Stacks and Queues" section of "Week 2".
although ArrayDeque<E> and LinkedList<E> have both implemented Deque<E> Interface, but the ArrayDeque uses basically Object array E[] for keeping the elements inside its Object, so it generally uses index for locating the head and tail elements.
In a word, it just works like Deque (with all Deque's method), however uses array's data structure. As regards which one is better, depends on how and where you use them.
That's not always the case.
For example, in the case below linkedlist has better performance than ArrayDeque according to leetcode 103.
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
List<List<Integer>> rs=new ArrayList<>();
if(root==null)
return rs;
// 👇 here ,linkedlist works better
Queue<TreeNode> queue=new LinkedList<>();
queue.add(root);
boolean left2right=true;
while(!queue.isEmpty())
{
int size=queue.size();
LinkedList<Integer> t=new LinkedList<>();
while(size-->0)
{
TreeNode tree=queue.remove();
if(left2right)
t.add(tree.val);
else
t.addFirst(tree.val);
if(tree.left!=null)
{
queue.add(tree.left);
}
if(tree.right!=null)
{
queue.add(tree.right);
}
}
rs.add(t);
left2right=!left2right;
}
return rs;
}
}
Time complexity for ArrayDeque for accessing a element is O(1) and that for LinkList is is O(N) to access last element. ArrayDeque is not thread safe so manually synchronization is necessary so that you can access it through multiple threads and so they they are faster.
This were the questions I was asked in the interview fews days back and I was not sure about the approach. Suggestions would be highly appreciated:
How can I have implement PriorityQueue interface to get queue() method in O(1) and dequeue() method in O(n).
How can I have implement PriorityQueue interface to get queue() method in O(n) and dequeue() method in O(1).
Thanks.
A typical PriorityQueue implementation would use a Heap to get O(lg n) performance for the "add" operation, so O(n) performance will be even easier.
For example, you could use a vector or linked list as the underlying data structure. For O(1) "add" you can simply add the new value to the end and for O(n) "remove" you can do a linear search for the min value. Conversely, for O(n) "add" you can do a linear scan to find the next largest value then insert before it, for O(1) remove you can simply remove the first element of the list.
queue() method in O(1) and dequeue() method in O(n):
Use a linked list and simply add every new entry directly to the head of the list in queue(). In dequeue() iterate the list and remove and return the entry with the highest priority.
queue() method in O(n) and dequeue() method in O(1):
Use a linked list again. But this time in queue() you iterate over the entries to put the new entry into it's priority sorted position (this is actually one step of an insertion sort). In dequeue() you can now always remove and return the first element of the list.
Just take a look at:
http://www.docjar.com/html/api/java/util/PriorityQueue.java.html
Remember, all good programmers copy good code :P
I assume you have the basic understanding about data structures, list, maps, etc. If you dont, understanding how this work will not make much sense, instead go and investigate about the subject further.
I would have said that PriorityQueue isn't an interface, it's a class, and I wouldn't implement anything that was O(n) if I could help it.
For an O(1) approach to the queue() method you must keep track of the last element of your queue, so that you can easily append one more after it, regardless the size of your queue.
For an O(n) in queue() and O(1) in dequeue() you need to keep track of the first element of your queue in a variable, so that regardless the number of elements within it, you can remove the first from the list with always a single set of instructions (no iterations).
In each of both cases you just add one extra variable to your class.
Wikipedia has a solution for this--
http://en.wikipedia.org/wiki/Priority_queue#Naive_implementations
For O(1) insertion, add element to the current location and for dequeue in O(n) perform a search based on priority..
For O(n) insertion perform the search initially based on priority and add the element and for dequeue in O(1) just remove the element from the beginning or from 0th location...
The code in this example can help you understand more clearly.
http://www.java-forums.org/java-lang/7449-how-implement-priority-queue-java.html
In the above example, the dequeue takes O(1) and insertion takes O(n)