Java Notes
Complete guide to Java PriorityQueue — binary heap implementation, min-heap and max-heap, internal working, heapify operations, comparison with other queues, and practical applications.
What is PriorityQueue?
java.util.PriorityQueue is a queue where elements are dequeued based on priority (not insertion order). By default, it's a min-heap — the smallest element (by natural ordering or comparator) is always at the head.
public class PriorityQueue<E>
extends AbstractQueue<E>
implements SerializableKey characteristics:
- Not FIFO — elements come out in priority order (smallest first by default)
- Backed by a binary heap (array-based)
- O(log n) for offer/poll, O(1) for peek
- Not thread-safe — use
PriorityBlockingQueuefor concurrency - No null elements
- No capacity limit (grows dynamically)
Time Complexity
| Operation | Time Complexity | Notes |
|---|---|---|
| ----------- | :-: | --- |
offer(E e) / add(E e) | O(log n) | Sift up |
poll() / remove() | O(log n) | Sift down |
peek() / element() | O(1) | Just return root |
remove(Object o) | O(n) | Linear search + sift |
contains(Object o) | O(n) | Linear search |
size() | O(1) | Stored field |
toArray() | O(n) | Copy array |
| Construction from collection | O(n) | Heapify (Floyd's algorithm) |
Why Construction is O(n), Not O(n log n)?
Building a heap from an unsorted array uses Floyd's bottom-up heapify, which runs in O(n) — more efficient than inserting elements one by one.
Basic Usage
import java.util.*;
public class PriorityQueueDemo {
public static void main(String[] args) {
// Min-heap (default) — smallest first
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
minHeap.offer(40);
minHeap.offer(10);
minHeap.offer(30);
minHeap.offer(20);
minHeap.offer(50);
System.out.println("Peek (min): " + minHeap.peek()); // 10
System.out.println("\nPolling (ascending order):");
while (!minHeap.isEmpty()) {
System.out.print(minHeap.poll() + " ");
}
// Output: 10 20 30 40 50
// Max-heap — largest first
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Comparator.reverseOrder());
maxHeap.offer(40);
maxHeap.offer(10);
maxHeap.offer(30);
maxHeap.offer(20);
maxHeap.offer(50);
System.out.println("\n\nPolling (descending order):");
while (!maxHeap.isEmpty()) {
System.out.print(maxHeap.poll() + " ");
}
// Output: 50 40 30 20 10
}
}PriorityQueue: [1, 3, 2, 5, 4] Peek (min): 1 Poll: 1 Poll: 2 Poll: 3 Poll: 4 Poll: 5 Max-Heap (reverse order): Poll: 5 Poll: 4 Poll: 3
Queue Interface Methods
| Operation | Throws Exception | Returns null/false |
|---|---|---|
| Insert | add(e) → IllegalStateException | offer(e) → false |
| Remove | remove() → NoSuchElementException | poll() → null |
| Examine | element() → NoSuchElementException | peek() → null |
For PriorityQueue, add() and offer() behave identically (no capacity limit), but offer() is preferred style.
Custom Priority with Comparator
Output:
Practical Applications
1. Finding K Largest Elements
Time: O(n log k) | Space: O(k)
2. Merge K Sorted Lists
Time: O(N log k) where N = total elements, k = number of lists
3. Dijkstra's Shortest Path (Concept)
4. Running Median
public class RunningMedian {
// Max-heap for lower half
PriorityQueue<Integer> lower = new PriorityQueue<>(Comparator.reverseOrder());
// Min-heap for upper half
PriorityQueue<Integer> upper = new PriorityQueue<>();
public void addNumber(int num) {
lower.offer(num);
upper.offer(lower.poll()); // Balance: move max of lower to upper
if (upper.size() > lower.size()) {
lower.offer(upper.poll()); // Keep lower same or 1 larger
}
}
public double getMedian() {
if (lower.size() > upper.size()) {
return lower.peek();
}
return (lower.peek() + upper.peek()) / 2.0;
}
}Important Behaviors
Iteration Order ≠ Priority Order!
PriorityQueue<Integer> pq = new PriorityQueue<>(Arrays.asList(5, 1, 3, 2, 4));
// WRONG — iterator does NOT return elements in priority order!
for (int num : pq) {
System.out.print(num + " ");
}
// Output might be: 1 2 3 5 4 (heap order, NOT sorted!)
// CORRECT — poll() gives priority order
while (!pq.isEmpty()) {
System.out.print(pq.poll() + " ");
}
// Output: 1 2 3 4 5 (sorted)No Random Access
// Can't access element at index — it's a queue, not a list
// pq.get(2); // No such method!Constructors
// Default min-heap, initial capacity 11
PriorityQueue<Integer> pq1 = new PriorityQueue<>();
// Custom initial capacity
PriorityQueue<Integer> pq2 = new PriorityQueue<>(100);
// Custom comparator (max-heap)
PriorityQueue<Integer> pq3 = new PriorityQueue<>(Comparator.reverseOrder());
// From collection (O(n) heapify)
PriorityQueue<Integer> pq4 = new PriorityQueue<>(Arrays.asList(5, 3, 8, 1, 2));
// Capacity + Comparator
PriorityQueue<String> pq5 = new PriorityQueue<>(10,
Comparator.comparingInt(String::length));Thread Safety
// PriorityQueue is NOT thread-safe
// Option 1: PriorityBlockingQueue (concurrent, unbounded)
BlockingQueue<Integer> pbq = new PriorityBlockingQueue<>();
pbq.put(5); // Never blocks (unbounded)
int val = pbq.take(); // Blocks if empty
// Option 2: Synchronized wrapper (less efficient)
Queue<Integer> syncQ = new PriorityQueue<>();
// No Collections.synchronizedQueue() — use PriorityBlockingQueue insteadCommon Mistakes
1. Assuming Iterator Gives Sorted Output
// WRONG — forEach/iterator doesn't give sorted order!
pq.forEach(System.out::println); // Not in priority order!
// CORRECT — poll() gives sorted order
while (!pq.isEmpty()) System.out.println(pq.poll());2. Adding Null
pq.offer(null); // NullPointerException!3. Modifying Elements After Adding
// If you change an element's priority after it's in the queue,
// the heap property is violated!
Task task = new Task("bug", 3);
pq.offer(task);
task.setPriority(1); // Heap doesn't know about this change!
// Fix: remove and re-add
pq.remove(task);
task.setPriority(1);
pq.offer(task);4. Confusing with Sorting
// PriorityQueue is NOT for sorting a list
// Use Collections.sort() or Arrays.sort() for that
// PriorityQueue is for dynamic "always know the min/max" scenariosPriorityQueue vs TreeSet
| Feature | PriorityQueue | TreeSet |
|---|---|---|
| Purpose | Access minimum quickly | All sorted, unique elements |
| Duplicates | Allowed | Not allowed |
| peek()/first() | O(1) | O(log n) |
| offer()/add() | O(log n) | O(log n) |
| remove(element) | O(n) | O(log n) |
| Iteration order | NOT sorted | Sorted |
| Range queries | No | Yes (subSet, etc.) |
Interview Questions
Q1: How does PriorityQueue work internally?
A: It uses a binary min-heap stored in an array. The smallest element is always at index 0 (root). Insert uses sift-up, remove uses sift-down to maintain the heap property.
Q2: What is the time complexity of PriorityQueue operations?
A: offer/poll: O(log n), peek: O(1), remove(Object): O(n), contains: O(n).
Q3: Does iterating a PriorityQueue give sorted output?
A: No! The iterator traverses the internal array (heap order), not priority order. Only poll() returns elements in priority order.
Q4: How do you create a max-heap PriorityQueue?
A: Use new PriorityQueue<>(Comparator.reverseOrder()) or new PriorityQueue<>((a, b) -> b - a).
Q5: Can PriorityQueue contain null or duplicates?
A: No nulls (NullPointerException). Yes duplicates (it's not a Set).
Q6: What is the difference between PriorityQueue and PriorityBlockingQueue?
A: PriorityBlockingQueue is thread-safe and supports blocking operations (take() blocks when empty). PriorityQueue is not thread-safe and not blocking.
Q8: Why does printing PriorityQueue not show elements in sorted order?
A: PriorityQueue is backed by a binary min-heap, which only guarantees that the root (index 0) is the minimum element. The internal array representation doesn't store elements in fully sorted order — only the heap property is maintained. To get sorted order, you must repeatedly call poll().
Q9: How do you create a max-heap PriorityQueue?
A: Pass Comparator.reverseOrder() or Collections.reverseOrder() to the constructor: new PriorityQueue<>(Comparator.reverseOrder()). Or use a custom comparator: new PriorityQueue<>((a, b) -> b - a). This makes poll() return the maximum element instead of minimum.
Q10: What is the time complexity of PriorityQueue operations?
A: offer()/add(): O(log n) — element bubbles up. poll()/remove(): O(log n) — root removed, last element sifts down. peek(): O(1) — just returns root. contains(): O(n) — linear scan. remove(Object): O(n) — find element + O(log n) restructure.
Q11: Can PriorityQueue contain duplicate elements?
A: Yes! Unlike Set implementations, PriorityQueue allows duplicate elements. Multiple elements with the same priority coexist in the heap. However, null elements are NOT allowed (throws NullPointerException).
Q12: What is the difference between PriorityQueue and TreeSet?
A: PriorityQueue: allows duplicates, only guarantees min/max at head, O(log n) insert/remove, O(n) for arbitrary element. TreeSet: no duplicates, ALL elements sorted, O(log n) for all operations including arbitrary access, supports range queries. Use PriorityQueue for producer-consumer; TreeSet for sorted unique collection.
Summary
| Aspect | PriorityQueue |
|---|---|
| Structure | Binary heap (array-based) |
| Default order | Min-heap (smallest first) |
| peek() | O(1) — instant access to minimum |
| offer()/poll() | O(log n) |
| Iteration | NOT in priority order |
| Null | Not allowed |
| Duplicates | Allowed |
| Thread-safe | No (use PriorityBlockingQueue) |
| Best for | Top-K problems, scheduling, Dijkstra |
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for PriorityQueue in Java.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Java Master Course topic.
Search Terms
java-master-course, java master course, java, master, course, collections, framework, queue
Related Java Master Course Topics