Java Priority Queue Interface Implementation - java

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)

Related

Is there a way to get the last element of a list faster than O(n) in Java?

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.

Why not use ListIterator for full LinkedList Operation?

My main question is if ListIterator or Iterator class reduces the time taken for removal of the elements from a given LinkedList and the same can be said while adding elements in the same given LinkedList using any one of the following classes above. What's the point of using the inbuilt functions of LinkedList class itself? Why should we perform any of the operations through LinkedList functions when we can use the ListIterator functions for better performance?
A ListIterator can indeed efficiently remove the node on which it is positioned. You can thus create a ListIterator, use next() two times to move the cursor, and then remove the node instantly. But evidently you did a lot of work before the actual removal.
Using ListIterator.remove is not more efficient "time complexity"-wise than removing through the LinkedList.remove(int index) if you need to construct the iterator. The LinkedList.remove method takes O(k) time, with k the index of the item you wish to remove. Removing this element with the ListIterator has the same timecomplexity since: (a) we create a ListIterator in constant time; (b) we call .next() k times, each operation in O(1); and (c) we call .remove() which is again O(1). But since we call .next() k times, this is thus an O(k) operation as well.
A similar situation happens for .add(..) on an arbitrary location (an "insert"), except that we here of course insert a node, not remove one.
Now since the two have the same time complexity, one might wonder why a LinkedList has such remove(int index) objects in the first place. The main reason is programmer's convenience. It is more convenient to call mylist.remove(5), than to create an iterator, use a loop to move five places, and then call remove. Furthermore the methods on a linked list guard against some edge-cases like a negative index, etc. By doing this manually you might end removing the first element, which might not be the intended behaviour. Finally code written is sometimes read multiple times. If a future reader reads mylist.remove(5), they understand that it removes the fifth element, wheres a solution with looping will require some extra brain cycles to understand what that part is doing.
As #Andreas says, furthermore the List interface defines these methods, and hence the LinkedList<T> should implement these.

How can I peek the tail of a java.util.PriorityQueue?

So I am playing with the source code of the java.util.PriorityQueue. You can check it here: http://kickjava.com/src/java/util/PriorityQueue.java.htm
I am in need to peek the tail of the queue. This class only offers peeking the head of the queue. Is there an easy way that I can modify this class to allow me to pick the tail?
I am looking for any change / smart hack in this class to allow me to do that. My first try was to peek queue[size] but it did not work.
Java's PriorityQueue, like most priority queues, is implemented with a heap.
A heap is a data structure that maintains only the property that all parents are less than their children, or all parents are greater than their children. There is no inherent ordering among children.
Thus, the only way to find the tail would be to do a linear search among the bottom layer, which costs O(n) time for a size n priority queue.
Yes, but the at the cost of extra space complexity:
PriorityQueue<Integer> pqNew = new PriorityQueue<>(java.util.Collections.reverseOrder());
Now add the elements of your PriorityQueue into this pqNew.
Therefore, pqNew.peek() will give you the required answer i.e. the tail element of your original PriorityQueue.
How about use toArray() method and access the last position?
PriorityQueue<Integer> pq = new PriorityQueue<>(3);
pq.offer(1); pq.offer(2); pq.offer(3);
System.out.println((int) pq.toArray()[pq.size()-1]);

How does java implement the conversion of LinkedList to ArrayList in Java?

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.

Java ListIterator Performance

I was reading a thread here about the performance of java ArrayList and LinkedList. There is an answer from Mr Kevin Brock that reads the following.
"Linked list add is not always O(1)
[or this should say addLast() is
O(1)]. This is only true if done from
within a ListIterator. The add methods
in Java's LinkList implementation must
search through the list if additions
are not on the head or tail."
I din't understand what he meant by "only if done through ListIterator". Does it mean there is a data structure within the linkedlist that holds the reference of each index and as soon as we get the listiterator from a certain index, listiterator is returned straight away without walking through the list to find that index?
Thanks guys!
It means that iterator points to list nodes directly; and so access via get(int) will be O(N), but iterator.next() wil be O(1). Latter has direct reference and does not need to traverse anything; former will need to traverse from head of the list.
If you add to a LinkedList where the ListIterator is pointing to, it is O(1). This is the same as adding to the start of the LinkedList or the end of an ArrayList.
The comment refers to the two argument add method, [add(int,E)][1]. Assuming a linearly distributed index, then this will be O(n) as the list needs to be iterated through to find the appropriate node. It does not apply to add(E).
[1]: http://download.oracle.com/javase/6/docs/api/java/util/LinkedList.html#add(int, E)

Categories

Resources