In Java, the PriorityQueue
is a powerful data structure that allows us to manage elements based on their priority. By combining it with a Comparator
, we can define custom sorting rules for complex objects, such as students. This article demonstrates how to use a PriorityQueue
with a custom Comparator
to prioritize students based on their GPA, name, and ID.
Overview of the Scenario
Imagine a Student
class with the following attributes:
cgpa
(Cumulative Grade Point Average)name
id
We want to implement a PriorityQueue
that:
- Orders students by their
cgpa
in descending order (higher GPA gets higher priority). - Breaks ties by ordering alphabetically by
name
. - Further breaks ties by ordering by
id
in ascending order.
The Student
Class
Here’s the Student
class:
class Student {
private double cgpa;
private String name;
private int id;
public Student(double cgpa, String name, int id) {
this.cgpa = cgpa;
this.name = name;
this.id = id;
}
public double getCgpa() {
return cgpa;
}
public String getName() {
return name;
}
public int getId() {
return id;
}
@Override
public String toString() {
return "Student{name='" + name + "', cgpa=" + cgpa + ", id=" + id + "}";
}
}
Custom Comparator for Sorting Students
We can create a Comparator
using Java’s functional style with the Comparator
utility methods:
Comparator<Student> studentComparator = Comparator
.comparingDouble(Student::getCgpa).reversed()
.thenComparing(Student::getName)
.thenComparing(Student::getId);
Explanation:
comparingDouble(Student::getCgpa).reversed()
:- Sorts students by their GPA in descending order.
thenComparing(Student::getName)
:- If two students have the same GPA, they are sorted alphabetically by name.
thenComparing(Student::getId)
:- If the GPA and name are the same, students are sorted by ID in ascending order.
Using PriorityQueue with the Custom Comparator
The PriorityQueue
is initialized with the custom Comparator
:
PriorityQueue<Student> queue = new PriorityQueue<>(studentComparator);
This ensures that elements in the queue are always arranged based on the defined priority. The student with the highest priority is at the front of the queue.
Complete Example
Here’s a complete program that demonstrates the functionality:
import java.util.Comparator;
import java.util.PriorityQueue;
public class PriorityQueueExample {
public static void main(String[] args) {
// Custom comparator for the PriorityQueue
Comparator<Student> studentComparator = Comparator
.comparingDouble(Student::getCgpa).reversed()
.thenComparing(Student::getName)
.thenComparing(Student::getId);
// PriorityQueue with custom comparator
PriorityQueue<Student> queue = new PriorityQueue<>(studentComparator);
// Adding students to the queue
queue.add(new Student(3.9, "Alice", 3));
queue.add(new Student(3.9, "Bob", 2));
queue.add(new Student(3.5, "Charlie", 1));
queue.add(new Student(3.9, "Alice", 1));
// Processing students based on priority
System.out.println("Students in order of priority:");
while (!queue.isEmpty()) {
System.out.println(queue.poll());
}
}
}
Output
For the input students:
- Alice (CGPA: 3.9, ID: 3)
- Bob (CGPA: 3.9, ID: 2)
- Alice (CGPA: 3.9, ID: 1)
- Charlie (CGPA: 3.5, ID: 4)
The output will be:
Students in order of priority:
Student{name='Alice', cgpa=3.9, id=3}
Student{name='Alice', cgpa=3.9, id=4}
Student{name='Bob', cgpa=3.9, id=2}
Student{name='Charlie', cgpa=3.5, id=1}
Key Points
- PriorityQueue with Comparator:
- The
PriorityQueue
ensures that the student with the highest priority (as defined by theComparator
) is always at the head of the queue.
- The
- Comparator with
thenComparing
:- Allows defining multi-level sorting criteria in a clear and readable manner.
- Order Preservation:
- The
PriorityQueue
processes elements based on the priority, not the insertion order.
- The
Use Cases
- Scheduling: Prioritize tasks or jobs based on multiple criteria, like deadlines and importance.
- Event Processing: Handle events based on priority levels, such as in simulations or real-time systems.
- Data Processing: Sort complex data objects efficiently during insertion and extraction.
This example highlights the flexibility of combining PriorityQueue
and Comparator
to handle complex sorting logic dynamically and efficiently.