Java
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented Java
-
Section 4: Collections Framework
-
Section 5: Exception Handling
-
Section 6: Generics
-
Section 7: Functional Java
-
Section 8: Concurrency
-
Section 9: I/O and NIO
-
Section 10: JVM Internals
-
Section 11: Modern Java Features
-
Section 12: Build Tools and Project Structure
-
Section 13: Testing
-
Section 14: Databases and Persistence
-
Section 15: Networking
-
Section 16: Design and Best Practices
-
Section 17: Reflection and Annotations
-
Section 18: Logging and Diagnostics
-
Section 19: Date, Time, and Internationalization
-
Section 20: Java Platform Module System
-
Section 21: Security in Java
-
Section 22: Advanced Collections and Data Structures
-
Section 23: More Concurrency Patterns
-
Section 24: Compression, Files, and System Integration
-
Section 25: GUI Programming
-
Section 26: Practical Projects
-
Section 27: Data Structures and Algorithms
-
Section 28: Interview and Algorithm Practice
-
Section 29: JSON and Data Interchange
-
Section 30: More Concurrency Utilities
-
Section 31: More Collections and Streams Practice
-
Section 32: More File and System Programming
-
Section 33: Standard Library Deep Dive
-
Section 34: More Practice and Drills
-
Section 35: More Testing and Quality
-
Section 36: More Design Patterns and Architecture
-
Section 37: Career and Ecosystem
-
Section 38: More OOP and Architecture Practice
-
Section 39: More Enterprise Concepts
-
Section 40: Advanced JavaFX
-
Section 41: More Interview Practice
197: PriorityQueue and Heap-Based Structures
A few years ago, I was reviewing code for a colleague who had built a task-scheduling system for a background processing engine. He was using a standard ArrayList to hold the tasks and calling Collections.sort() every single time a new task was added to ensure the highest-priority job was always at the top. It worked perfectly during the demo with ten tasks. But when we hit production with ten thousand tasks per second, the CPU usage spiked to 90% and the system practically ground to a halt. The bottleneck was obvious: sorting an entire list over and over is a massive waste of resources when you only actually care about the single most important element.
That's where the PriorityQueue comes in. Unlike a standard Queue, which follows a strict First-In-First-Out (FIFO) order, a PriorityQueue ensures that the element with the "highest priority" is always at the head of the queue. In Java, this is implemented using a binary heap. If you're not familiar with heaps, don't let the name intimidate you; it's essentially a tree-based structure that keeps the smallest (or largest) element at the root, allowing us to insert new items and remove the top item in logarithmic time—O(log n)—which is vastly more efficient than re-sorting a list.
The Mechanics of the Min-Heap
By default, Java's PriorityQueue is a min-heap. This means the element that compares as "least" will be the first one served. I've seen many developers get tripped up by this, expecting the largest number to come out first. If you put the integers 10, 1, and 5 into a PriorityQueue, the first call to poll() will give you 1, not 10.
PriorityQueue<Integer> pq = new PriorityQueue<>();
pq.add(10);
pq.add(1);
pq.add(5);
System.out.println(pq.poll()); // Outputs 1
System.out.println(pq.poll()); // Outputs 5
One thing to keep in mind: the PriorityQueue does not guarantee any specific order when you iterate over it using an iterator or a for-each loop. It only guarantees that the head of the queue is the smallest element. If you need the whole collection sorted, you'll have to poll the elements out one by one.
Defining Custom Priority with Comparators
In the real world, you're rarely just storing integers. You're usually storing objects—like a Ticket or a UserRequest—and you need to define what "priority" actually means for those objects. You have two main ways to handle this: implementing the Comparable interface within your class, or passing a Comparator to the PriorityQueue constructor.
I generally prefer the Comparator approach because it's more flexible. It allows you to change the priority logic without modifying the data class itself. For example, if you want a max-heap (where the highest value comes first), you can simply use Collections.reverseOrder() or a custom lambda expression.
class Task {
String name;
int priorityLevel;
Task(String name, int priorityLevel) {
this.name = name;
this.priorityLevel = priorityLevel;
}
}
// We want the highest priorityLevel to be processed first
PriorityQueue<Task> taskQueue = new PriorityQueue<>((a, b) -> b.priorityLevel - a.priorityLevel);
taskQueue.add(new Task("Fix minor typo", 1));
taskQueue.add(new Task("Fix production crash", 10));
taskQueue.add(new Task("Update documentation", 2));
while (!taskQueue.isEmpty()) {
System.out.println("Processing: " + taskQueue.poll().name);
}
// Output:
// Processing: Fix production crash
// Processing: Update documentation
// Processing: Fix minor typo
Notice the lambda (a, b) -> b.priorityLevel - a.priorityLevel. By subtracting a from b instead of the usual a - b, we effectively flip the natural ordering, turning our min-heap into a max-heap. Just be careful with subtraction if your values can be very large or negative, as you might hit integer overflow; in those cases, Integer.compare(b.val, a.val) is the safer, professional choice.
📋 Practical Task
Exercise: Hospital Emergency Room Triage System
You are tasked with building a triage system for a hospital. Patients arrive at different times with different severity levels. The hospital must always treat the patient with the highest severity first. If two patients have the same severity, the one who arrived first should be treated first (FIFO).
Requirements:
- Create a
Patientclass with the following fields:String name,int severity(1 to 10, where 10 is critical), andlong arrivalTime. - Implement a
TriageSystemclass that uses aPriorityQueueto manage patients. - The
PriorityQueuemust be configured so that:- Patients with higher severity are polled first.
- If severity is equal, the patient with the lower
arrivalTime(the one who arrived earlier) is polled first.
- Write a
mainmethod to simulate the following scenario:- Patient "Alice" arrives with severity 5.
- Patient "Bob" arrives with severity 10.
- Patient "Charlie" arrives with severity 10.
- Patient "David" arrives with severity 2.
- Poll and print the patients in the order they should be treated.
There are no comments for now.