5.8. Creating a Priority Queue

Problem

You need to prioritize objects: removing higher priority objects from a Collection before lower priority objects.

Solution

Use a PriorityBuffer to hold objects to be prioritized. Objects will be removed from this Buffer according to a priority generated with a Comparator. Whenever the remove( ) method is called on this Buffer implementation, a PriorityBuffer uses the Comparator to sort its contents, returning the element of greatest priority. Using a PriorityBuffer without a Comparator causes the buffer to prioritize objects by natural order, casting each object to Comparable and comparing objects with the compareTo( ) method; all objects must implement the Comparable interface if no Comparator is supplied. The following example demonstrates the use of a PriorityBuffer without supplying a Comparator :

import java.util.*;
import org.apache.commons.collections.Buffer;
import org.apache.commons.collections.buffers.PriorityBuffer;

// Create a PriorityBuffer with no Comparator
Buffer priority = new PriortyBuffer( );
priority.add( new Long( 2 ) );
priority.add( new Long( 1 ) );
priority.add( new Long( 20 ) );
priority.add( new Long( 7 ) );
priority.add( new Long( 18 ) );
priority.add( new Long( 1 ) );

// Print the results in priority order
Iterator priorityIterator = priority.iterator( );
while( priorityIterator.hasNext( ) ) {
    Long value = (Long) priority.next( );
    System.out.prinltn( "Value: " + value );
}

The previous example removes values from the buffer based on a natural order, and the following output is produced:

Value: 20
Value: 18
Value: 7
Value: 2
Value: 1
Value: 1

Discussion

A PriorityBuffer, like all Buffer implementations, is defined by the logic to select which object to remove. If you’ve ever visited an emergency room, you are already familiar with the inner workings of the PriorityBuffer. When a patient enters the emergency room, his or her condition is evaluated by a nurse who then assigns a severity. When a doctor moves to the next patient, she chooses the next patient based on severity and how long each patient has been waiting. A patient with a critical, life-threatening condition will be treated before an individual with a headache—the critical patient has a higher priority in the Buffer.

The following example models an emergency waiting room with a PriorityBuffer. Assume that you have a Patient bean with name, severity, and checkIn properties, which is defined in Example 5-5. A patient’s severity is a number from 0 to 10, 0 being the lowest severity and 10 being the highest. A critical patient would be assigned a priority of 10, and a patient with a bad cold would be assigned a severity of 0. A patient also has a checkIn time: this is the time he is admitted to the waiting room, and it is used as a tie-breaker to determine priority when two patients have the same severity.

Example 5-5. A Patient object

package com.discursive.jccook.collections.buffers;

public class Patient {
    private String name;
    private Integer severity;
    private Date checkIn;

    public class Patient( ) {}

    public String getName( ) { return name; }
    public void setName(String name) { this.name = name; }

    public Integer getSeverity( ) { return severity; }
    public void setSeverity(Integer severity) { this.severity = severity; }

    public Date getCheckIn( ) { return checkIn; }
    public void setCheckIn(Date checkIn) { this.checkIn = checkIn; }
}

The PatientPriorityComparator in Example 5-6 prioritizes patients by severity of condition and time since check-in. A patient with a more severe condition takes priority over a patient with a less severe condition who has been waiting longer, and, if two patients have the same severity, the one who has been waiting longer gets a higher priority. If this Comparator is used to sort an array of Patient objects, the most critical patient would be at the last index, and the least critical would be at the first index.

Example 5-6. A Comparator to sort Patient objects by priority

package com.discursive.jccook.collections.buffers;

import java.util.Comparator;

public PatientPriorityComparator implements Comparator {

    public int compare(Object o1, Object o2) {
        int comparison = -1;

        if( o1 instanceof Patient &&
            o2 instanceof Patient ) {

            Patient p1 = (Patient) o1;
            Patient p2 = (Patient) o2;

            comparison = p1.getSeverity( ).compareTo( p2.getSeverity( ) );

                if( comparison == 0 ) {
                    comparison = 
                    p1.getCheckIn( ).compareTo( p2.getCheckIn( ) );
            }
        }
        return comparison;
    }
}

When using the PriorityBuffer with a PatientPriorityComparator, Patient objects are added to the Buffer and remove( ) returns the Patient with the highest priority. Using a PriorityBuffer means that you do not need to worry about constantly resorting a Collection by priority; this logic is completed automatically every time an object is removed from the Buffer. In other words, you are delegating responsibility to a Buffer; it takes care of the sorting and selecting on an as-needed basis.

Example 5-7 adds three Patient objects to a PriorityBuffer: John Doe 1 has an ear ache, John Doe 2 has a broken back, and Jane Doe 3 has a concussion. Both John 2 and Jane 3 have serious conditions, and, since John 2 checked in before Jane 3, John 2 has a higher priority than Jane 3. John 1’s condition is not nearly as critical; therefore, his priority is much lower, and he is treated last.

Example 5-7. Using a prioritizing buffer

package com.discursive.jccook.collections.buffers;

public class WaitingRoomApp {

    public static void main(String[] args) {
        WaitingRoomApp example = new WaitingRoomApp( );
        example.start( );
    }

    public void start( ) {
        Buffer patients = 
            new PriorityBuffer( new PatientPriorityComparator( ) );

        Patient johnDoe1 = new Patient( );
        johnDoe1.setName( "John Doe 1" );
        johnDoe1.setSeverity( new Integer( 7 ) );
        johnDoe1.setCheckIn( new Date( ) );
        patients.add( johnDoe1 );

        Patient johnDoe2 = new Patient( );
        johnDoe2.setName( "John Doe 2" );
        johnDoe2.setSeverity( new Integer( 9 ) );
        johnDoe2.setCheckIn( new Date( ) );
        patients.add( johnDoe2 );

        Patient janeDoe3 = new Patient( );
        janeDoe3.setName( "Jane Doe 3" );
        janeDoe3.setSeverity( new Integer( 9 ) );
        janeDoe3.setCheckIn( new Date( ) );
        patients.add( janeDoe3 );

         while( patients.size( ) > 0 ) {
            Patient patient = (Patient) patients.remove( );
            System.out.println( "Patient: " + patient.getName( ) );
        }
    }
}

As each Patient is treated, the patient’s name is printed to the console:

Patient: John Doe 2
Patient: Jane Doe 3
Patient: John Doe 1

See Also

A PriorityBuffer in Jakarta Commons Collections is analogous to a PriorityQueue in Java 5.0. For information about PriorityQueue and other important changes to the Collections framework in Java 5.0, see http://java.sun.com/j2se/1.5.0/docs/api/index.html.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.224.73.175