Search code examples
javalinked-listqueuepriority-queuecomparator

Making a Java PriorityQueue into a stable priority queue


I'm trying to implement a stable (first in first out) priority queue in Java. Supposing that the key is a name and the value is an age, I know I can make an unstable priority queue like this:

Queue<Map.Entry<String, Integer>> pq = new PriorityQueue<Map.Entry<String, Integer>>(100, ageComparator);

This does pretty much everything that I need it to, except that it doesn't maintain order of key-value pairs as I insert them (or remove them).

I've found a "work around" by making a LinkedList, which offers essentially all of the same functionality, except that it doesn't include a constructor with a comparator option, and I feel that it must be slower since I maintain value ordering by calling Collections.sort() after each queue operation.

So I guess that really there are two options that I'm interested in. First, how could I edit the PriorityQueue above to maintain insertion and removal order? Or second, how could I force my LinkedList option to use a comparator immediately rather than having to call a sort on each operation? Thanks!

EDIT:

Thanks for the good question in the first comment that was posted. By FIFO, I mean that for key-value pairs with equal values, the pair which is put in first should be extracted first.


Solution

  • You need something like this:

    import java.util.AbstractMap;
    import java.util.Comparator;
    import java.util.PriorityQueue;
    import java.util.concurrent.atomic.AtomicInteger;
    
    public class PriorityTest {
      @SuppressWarnings("serial")
      private static class Entry extends AbstractMap.SimpleEntry<String, Integer> {
        private final static AtomicInteger seq = new AtomicInteger(0);
        final int order;
        public Entry(final String _key, final Integer _value) {
          super(_key, _value);
          order = seq.incrementAndGet();
        }
      }
    
      private static class OrderedComparator implements Comparator<Entry> {
        @Override
        public int compare(final Entry _e1, final Entry _e2) {
          int r = _e1.getValue().compareTo(_e2.getValue());
          if (r == 0)
            return Integer.compare(_e1.order, _e2.order);
          return r;
        }
      }
    
      public static void main(String[] args) {
        final PriorityQueue<Entry> pq = new PriorityQueue<Entry>(10, new OrderedComparator());
        pq.add(new Entry("Jane", 22));
        pq.add(new Entry("John", 15));
        pq.add(new Entry("Bill", 45));
        pq.add(new Entry("Bob", 22));
        while(!pq.isEmpty()) {
          System.out.println(pq.remove());
        }
      }
    }