I know, queue follow FIFO(First in first out) order, but I am not sure why the following output appears with below java sample program
JAVA Sample
public static void main(String args[]) {
Queue<String> q = new PriorityQueue<String>();
q.add("3");
q.add("1");
q.add("2");
Iterator<String> itr = q.iterator();
while (itr.hasNext()) {
System.out.println(itr.next() + " ");
}
}
OUTPUT :
1
3
2
As per Java doc of java.util.PriorityQueue.PriorityQueue()
Creates a PriorityQueue with the default initial capacity (11) that orders its elements according to their natural ordering.
Q1) Could any body please explain why the output is 1 3 2 and how
the natural order works here.
Q2) I have checked about natural ordering and its related to the
Comparable/Comparor but doesn't they are for
Sorting(Ascending/Descending) Order only??
The PriorityQueue in Java is a datastructure, that sorts the elements it contains. Excerpt from the Javadoc:
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.
The Problem with the unordered output comes from the iterator implementation. Another excerpt, this time from the iterator() method:
Returns an iterator over the elements in this queue. The iterator does not return the elements in any particular order.
So you don't java a fixed order with the iterator. If you use the poll() method in a loop you would get all given elements in ascending order.
If you are looking for a Queue in the FIFO-sense you may have a look at the LinkedList and only use the addFirst() and getLast() methods.
Related
I define a maximum priority queue as below:
PriorityQueue<Integer> queue = new PriorityQueue<>(Collections.reverseOrder());
queue.add(25);
queue.add(3);
queue.add(1);
queue.add(3);
queue.add(4);
I need to understand how this works especially when does the 1 gets the index of 2 only (not 4)?
Thanks.
It has no guaranteed order (https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/PriorityQueue.html):
The Iterator provided in method iterator() and the Spliterator provided in method spliterator() are 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()).
Normally you retrieve elements according to their natural order using the poll() method, for example:
while (!queue.isEmpty()) {
var element = queue.poll();
...
}
EDIT:
If you want to look at the internals of the class, this part of the code may be relevant (it basically uses a heap data structure):
/**
* Priority queue represented as a balanced binary heap: the two
* children of queue[n] are queue[2*n+1] and queue[2*(n+1)]. The
* priority queue is ordered by comparator, or by the elements'
* natural ordering, if comparator is null: For each node n in the
* heap and each descendant d of n, n <= d. The element with the
* lowest value is in queue[0], assuming the queue is nonempty.
*/
transient Object[] queue;
This class use structure called Heap, and store it in array.
You will receive objects in proper order when you poll them.
This question already has answers here:
The built-in iterator for java's PriorityQueue does not traverse the data structure in any particular order. Why?
(5 answers)
Closed 6 years ago.
I was learning Java and trying to learn priority queue in collections. I tried with below example from one website:
import java.util.*;
class S
{
public static void main(String args[])
{
PriorityQueue<String> queue=new PriorityQueue<String>();
queue.add("Amit");
queue.add("Vijay");
queue.add("Karan");
queue.add("Rahul");
queue.add("Jai");
System.out.println("iterating the queue elements:");
Iterator<String> itr=queue.iterator();
while(itr.hasNext())
{
System.out.println(itr.next());
}
}
}
here results came is below:
Amit
Jai
Karan
Vijay
Rahul`
I was expecting the result as :
Amit
Vijay
Karan
Rahul
Jai
I am not able to understand how the result changes from my expectation and what type of normal or default priority is used.
In case i want to get the same result as per my expectation, what should i do using prioiryqueue?
Please help me.
Here i want the exact cause of default ordering in priority queue.
Quoting javadoc of PriorityQueue:
The Iterator provided in method iterator() is not guaranteed to traverse the elements of the priority queue in any particular order.
As you can see, the ordering of the PriorityQueue doesn't matter when using iterator(). Now if you began to take values from the queue using poll(), you would get the values in lexicographical order, i.e. the natural order of String.
If you want a queue that returns items in insertion order, use a regular Queue implementation like LinkedList or ArrayDeque.
Is there a collection that preserves reversible duplicate insertion order?
Specifically, if I insert the following items:
1
2
3
1
I want to be able to iterate over them and receive them in the following order:
1
3
2
That is, I want them in descending insertion order with duplicate insertions causing a reorder. Guava's LinkedListMultimap is the closest I've found, but it doesn't support descending traversal.
Java's LinkedHashSet doesn't work because it doesn't allow descending traversal.
I could also use an LRU cache, but most LRU libraries I've found don't support retrieving objects in LRU order.
Does this thing have a standard name?
How about using a LinkedHashSet and whenever you detect that the item is in there you remove it and reinsert it? That's the only way to guarantee the insertion order is what you expect (or the inverse thereof).
You can iterate over the LinkedHashSet by creating a LinkedList over the LinkedHashSet and reversing over it in any way you like, e.g. by using Guava's Lists.reverse method.
Try ListOrderedSet class of org.apache.commons.collections4.set.
For example:
listOrderedSet.add(1,1);
listOrderedSet.add(1,2);
listOrderedSet.add(1,3);
listOrderedSet.add(1,1);
This will give you the expected out put.
JEP 431: Sequenced Collections is a proposed improvement to the Java collections library which (among other things) adds methods to a number of collection types including LinkedHashSet. It adds a reversed() method to provide reversed view of the collection, and also adds an addFirst method to add an element to the front of the collection. If this is added to Java as proposed, either method could be used to get you exactly what you're requesting.
SequencedSet<Integer> set = new LinkedHashSet<>();
set.addFirst(1);
set.addFirst(2);
set.addFirst(3);
set.addFirst(1);
// 1 then 3 then 2
for (Integer i : set) {
System.out.println(i);
}
SequencedSet<Integer> set = new LinkedHashSet<>().reversed();
set.add(1);
set.add(2);
set.add(3);
set.add(1);
// 1 then 3 then 2 (I think)
for (Integer i : set) {
System.out.println(i);
}
This question already has answers here:
The built-in iterator for java's PriorityQueue does not traverse the data structure in any particular order. Why?
(5 answers)
Closed 7 years ago.
I am trying to use priority queue to keep an ordered list of integers. in a simple exaple like this:
PriorityQueue<Integer> queue = new PriorityQueue<>();
queue.offer(3000);
queue.offer(1999);
queue.offer(999);
for(Integer i : queue)
System.out.println(i);
This prints
999
3000
1999
This is not what I am expecting considering natural odering.
I simply want to iterate without removing or adding through the queue (which serves as a sorted list) WITH ordering. Can I still do that in a simple manner?
PriorityQueue is a collection optimized for finding the tail or head value quickly, using a partially ordered tree structure called heap (look it up on wikipedia). If you pop the elements, they will be ordered. If you want to iterate, use for example a SortedSet instead, which also stores the elements sorted.
This is a very sneaky problem with PriorityQueue: to quote the Api
The Iterator provided in method iterator() is 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()).
Use Poll instead to get the head which will be in order
Is there an existing List implementation in Java that maintains order based on provided Comparator?
Something that can be used in the following way:
Comparator<T> cmp = new MyComparator<T>();
List<T> l = new OrderedList<T>(cmp);
l.add(someT);
so that someT gets inserted such that the order in the list is maintained according to cmp
(On #andersoj suggestion I am completing my question with one more request)
Also I want to be able to traverse the list in sorted order without removing the elements, i.e:
T min = Const.SMALLEST_T;
for (T e: l) {
assertTrue(cmp.compare(min, e) >= 0);
min = e;
}
should pass.
All suggestions are welcome (except telling me to use Collections.sort on the unordered full list), though, I would prefer something in java.* or eventually org.apache.* since it would be hard to introduce new libraries at this moment.
Note: (UPDATE4) I realized that implementations of this kind of list would have inadequate performance. There two general approaches:
Use Linked structure (sort of) B-tree or similar
Use array and insertion (with binary search)
No 1. has problem with CPU cache misses
No 2. has problem with shifting elements in array.
UPDATE2:
TreeSet does not work because it uses the provided comparator (MyComparator) to check for equality and based on it assumes that the elements are equal and exclude them. I need that comparator only for ordering, not "uniqueness" filtering (since the elements by their natural ordering are not equal)
UPDATE3:
PriorityQueue does not work as List (as I need) because there is no way to traverse it in the order it is "sorted", to get the elements in the sorted order you have to remove them from the collection.
UPDATE:
Similar question:
A good Sorted List for Java
Sorted array list in Java
You should probably be using a TreeSet:
The elements are ordered using their natural ordering, or by a Comparator provided at set creation time, depending on which constructor is used.
Example:
Comparator<T> cmp = new MyComparator<T>();
TreeSet<T> t = new TreeSet<T>(cmp);
l.add(someT);
Note that this is a set, so no duplicate entries are allowed. This may or may not work for your specific use-case.
Response to new requirement. I see two potentials:
Do what the JavaDoc for PriorityQueue says:
This class and its iterator implement all of the optional methods of the Collection and Iterator interfaces. The Iterator provided in method iterator() is 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()).
I suspect this will yield the best performance given your requirements. If this is not acceptable, you'll need to better explain what you're trying to accomplish.
Build a List that simply sorts itself upon addition of new elements. This is a real pain... if you used a linked structure, you can do an efficient insertion sort, but locality is bad. If you used an array-backed structure, insertion sort is a pain but traversal is better. If iteration/traversal is infrequent, you could hold the list contents unsorted and sort only on demand.
Consider using a PriorityQueue as I suggested, and in the event you need to iterate in order, write a wrapper iterator:
class PqIter implements Iterator<T>
{
final PriorityQueue<T> pq;
public PqIter(PriorityQueue <T> source)
{
pq = new PriorityQueue(source);
}
#Override
public boolean hasNext()
{
return pq.peek() != null
}
#Override
public T next()
{ return pq.poll(); }
#Override
public void remove()
{ throw new UnsupportedOperationException(""); }
}
Use Guava's TreeMultiSet. I tested the following code with Integer and it seems to do the right thing.
import com.google.common.collect.TreeMultiset;
public class TreeMultiSetTest {
public static void main(String[] args) {
TreeMultiset<Integer> ts = TreeMultiset.create();
ts.add(1); ts.add(0); ts.add(2);
ts.add(-1); ts.add(5); ts.add(2);
for (Integer i : ts) {
System.out.println(i);
}
}
}
The below addresses the uniqueness/filtering problem you were having when using a SortedSet. I see that you also want an iterator, so this won't work.
If what you really want is an ordered list-like thing, you can make use of a PriorityQueue.
Comparator<T> cmp = new MyComparator<T>();
PriorityQueue<T> pq = new PriorityQueue<T>(cmp);
pq.add(someT);
Take note of what the API documentation says about the time properties of various operations:
Implementation note: this implementation provides O(log(n)) time for the enqueing and dequeing methods (offer, poll, remove() and add); linear time for the remove(Object) and contains(Object) methods; and constant time for the retrieval methods (peek, element, and size).
You should also be aware that the iterators produced by PriorityQueue do not behave as one might expect:
The Iterator provided in method iterator() is 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()).
I just noticed that Guava provides a MinMaxPriorityQueue. This implementation is array-backed, rather than the linked form provided in the JDK's PriorityQueue, and thus likely has different timing behavior. If you're doing something performance sensitive, you may wish to take a look. While the notes give slightly different (linear and logarithmic) big-O times, all those times should also be bounded, which may be useful.
There is not a List implementation per se that maintains ordering, but what you are likely looking for are implementations of SortedSet. A TreeSet is the most common. The other implementation, a ConcurrentSkipListSet is for more specific uses. Note that a SortedSet provides ordering, but does not allow duplicate entries, as does a List.
Refs:
Blog post PriorityQueue iterator is not ordered
SO question on PQ ordered iterator
I have a similar problem and I'm thinking of using a TreeSet. To avoid excluding "equal" elements I will modify the comparator so instead of returning 0 it will return a random number between (-1,1) or it will return always 1.
If you have no control over the Comparator or if you are using it for something else different than inserting this solution won't work for you.