Priority Queue

Introduction

We are often faced with a situation in which certain events/elements in life have higher or lower priorities than others. For example, university course prerequisites, emergency vehicles have priority over regular vehicles. A Priority Queue is like a queue, except that each element is inserted according a given priority. The simplest example is provided by real numbers and ≤ or ≥ relations over them. We can say that the smallest (or the largest) numerical value has the highest priority. In practice, priority queues are more complex than that. A priority queue is a data structure containing records with numerical keys (priorities) that supports some of the following operations:

Observe that a priority queue is a proper generalization of the stack (remove the newest) and the queue (remove the oldest).

Elementary Implementations

There are numerous options for implementing priority queues. We start with simple implementations based on use of unordered or ordered sequences, such as linked lists and arrays. The worst-case costs of the various operations on a priority queue are summarized in this table
 

 

 insert

 remove max

 remove

 find max

change priority

 merge

ordered array

N

1

N

1

N

N

ordered list

N

1

1

1

N

N

unordered array

1

N

1

N

1

N

unordered list

1

N

1

N

1

1


Later on in the course we will see another implementation of a priority queueu based on a binary heap.

Comparable and Comparator interfaces

The Comparable interface contains only one method with the following signature:

	public int compareTo(Object obj);
The returned value is negative, zero or positive depending on whether this object is less, equals or greater than parameter object. Note a difference between the equals() and compareTo() methods. In the following code example we design a class of playing cards that can be compared based on their values:
class Card implements Comparable<Card>
{
   private String suit;
   private int value;

   public Card(String suit, int value)
   {
      this.suit = suit;
      this.value = value;
   }
   public int getValue()
   {
      return value;
   }
   public String getSuit()
   {
      return suit;
   }
   public int compareTo(Card x)
   {
      return getValue() - x.getValue();
   }
}

It is important to recognize that if a class implements the Comparable interface than compareTo() and equals() methods must be correlated in a sense that if x.compareTo(y)==0, then x.equals(y)==true. The default equals() method compares two objects based on their reference numbers and therefore in the above code example two cards with the same value won't be equal. And a final comment, if the equals() method is overriden than the hashCode() method must also be overriden, in order to maintain the following properety: if x.equals(y)==true, then x.hashCode()==y.hashCode().

Suppose we would like to be more flexible and have a different way to compare cards, for example, by suit. The above implementation doesn’t allow us to do this, since there is only one compareTo method in Card. Java provides another interface which we can be uses to solve this problem:

public interface Comparator<AnyType>
{
   compare(AnyType first, AnyType second);
}

Notice that the compare() method takes two arguments, rather than one. Next we demonstrate the way to compare two cards by their suits, This method is defined in its own class that implements Comparator:

class SuitSort implements Comparator<Card>
{
   public int compare(Card x, Card y)
   {
      return x.getSuit().compareTo(  y.getSuit() );
   }
}

Objects that implement the Comparable interface can be sorted using the sort() method of the Arrays and Collections classes. In the following code example, we randomly generate a hand of five cards and sort them by value and then by suit:

String[] suits = {"Diamonds", "Hearts", "Spades", "Clubs"};
Card[] hand = new Card[5];
Random rand = new Random();

for (int i = 0; i < 5; i++)
   hand[i] = new Card(suits[rand.nextInt(4)], rand.nextInt(12));

System.out.println("sort by value");
Arrays.sort(hand);
System.out.println(Arrays.toString(hand));

System.out.println("sort by suit");
Arrays.sort(hand, new SuitSort() );
System.out.println(Arrays.toString(hand));

Objects can have several different ways of being compared. Here is another way of comparing cards: first by value and if values are the same then by suit:

class ValueSuitSort implements Comparator<Card>
{
   public int compare(Card x, Card y)
   {
      int v = x.getValue() - y.getValue();

      return ( v == 0) ? x.getSuit().compareTo(y.getSuit()) : v;
   }
}