Bird
Raised Fist0
DSA Rustprogramming

Priority Queue Introduction and Concept in DSA Rust

Choose your learning style10 modes available
Mental Model
A priority queue is like a line where people with higher importance get served first, no matter when they arrive.
Analogy: Imagine a hospital emergency room where patients with more serious conditions are treated before others, even if they arrived later.
Priority Queue:
[10] -> [5] -> [3] -> null
↑ highest priority at front
Dry Run Walkthrough
Input: Insert values 5, 10, 3 into an empty priority queue where higher numbers have higher priority.
Goal: To keep the queue ordered so the highest priority value is always at the front.
Step 1: Insert 5 into empty queue
[5] -> null
Why: First element becomes the front as queue was empty
Step 2: Insert 10, which has higher priority than 5
[10] -> [5] -> null
Why: 10 moves to front because it has higher priority than 5
Step 3: Insert 3, which has lower priority than 5 and 10
[10] -> [5] -> [3] -> null
Why: 3 goes to the end because it has lowest priority
Result:
[10] -> [5] -> [3] -> null
Annotated Code
DSA Rust
use std::cmp::Ordering;

#[derive(Debug)]
struct Node {
    value: i32,
    next: Option<Box<Node>>,
}

#[derive(Debug)]
struct PriorityQueue {
    head: Option<Box<Node>>,
}

impl PriorityQueue {
    fn new() -> Self {
        PriorityQueue { head: None }
    }

    fn insert(&mut self, value: i32) {
        let mut new_node = Box::new(Node { value, next: None });

        // If queue is empty or new value has higher priority than head
        if self.head.is_none() || self.head.as_ref().unwrap().value < value {
            new_node.next = self.head.take(); // link new node to current head
            self.head = Some(new_node); // new node becomes head
            return;
        }

        // Traverse to find correct position
        let mut current = self.head.as_mut().unwrap();
        while let Some(ref mut next_node) = current.next {
            if next_node.value < value {
                break; // found position where next node has lower priority
            }
            current = next_node;
        }

        // Insert new node
        new_node.next = current.next.take();
        current.next = Some(new_node);
    }

    fn print(&self) {
        let mut current = self.head.as_ref();
        while let Some(node) = current {
            print!("{} -> ", node.value);
            current = node.next.as_ref();
        }
        println!("null");
    }
}

fn main() {
    let mut pq = PriorityQueue::new();
    pq.insert(5);
    pq.insert(10);
    pq.insert(3);
    pq.print();
}
if self.head.is_none() || self.head.as_ref().unwrap().value < value {
check if queue is empty or new value has higher priority than current front
new_node.next = self.head.take();
link new node to current head to insert at front
self.head = Some(new_node);
make new node the new front of the queue
while let Some(ref mut next_node) = current.next {
traverse nodes to find correct insertion point
if next_node.value < value { break; }
stop when next node has lower priority than new value
new_node.next = current.next.take();
link new node to next node to insert in middle or end
current.next = Some(new_node);
insert new node after current node
OutputSuccess
10 -> 5 -> 3 -> null
Complexity Analysis
Time: O(n) because in worst case we traverse all nodes to find insertion point
Space: O(n) because each inserted element creates a new node
vs Alternative: Compared to a simple queue where insertion is O(1) at end, priority queue insertion is slower due to ordering but allows quick access to highest priority
Edge Cases
Empty queue
New element becomes the head immediately
DSA Rust
if self.head.is_none() || self.head.as_ref().unwrap().value < value {
Insert element with priority equal to existing node
New element is inserted after nodes with equal or higher priority
DSA Rust
while let Some(ref mut next_node) = current.next { if next_node.value < value { break; } }
Insert element with lowest priority
New element is inserted at the end of the queue
DSA Rust
new_node.next = current.next.take(); current.next = Some(new_node);
When to Use This Pattern
When you need to always access the highest priority item quickly, use a priority queue because it keeps elements ordered by priority.
Common Mistakes
Mistake: Inserting new elements only at the end without ordering
Fix: Traverse the queue to find the correct position based on priority before inserting
Mistake: Not updating the head when new element has highest priority
Fix: Check if new element has higher priority than head and update head pointer accordingly
Summary
A priority queue stores elements so the highest priority is always at the front.
Use it when you need to process items by importance rather than arrival order.
The key is inserting elements in order so the front is always the highest priority.

Practice

(1/5)
1. What is the main feature of a Priority Queue compared to a regular queue?
easy
A. It only stores elements of the same value
B. Elements are always dequeued in the order they were inserted
C. Elements are dequeued based on priority, not just order of insertion
D. It does not allow duplicate elements

Solution

  1. Step 1: Understand queue behavior

    A regular queue removes elements in the order they were added (FIFO).
  2. Step 2: Understand priority queue behavior

    A priority queue removes elements based on their priority, not just insertion order.
  3. Final Answer:

    Elements are dequeued based on priority, not just order of insertion -> Option C
  4. Quick Check:

    Priority Queue = Priority-based removal [OK]
Hint: Priority queue removes highest priority first, not oldest [OK]
Common Mistakes:
  • Confusing priority queue with FIFO queue
  • Thinking priority queue sorts elements permanently
  • Assuming priority queue disallows duplicates
2. Which of the following is the correct way to create a max-heap priority queue in Rust using std::collections::BinaryHeap?
easy
A. let mut pq = std::collections::BinaryHeap::min_heap();
B. let mut pq = std::collections::BinaryHeap::with_capacity(10i32);
C. let mut pq = std::collections::BinaryHeap::default(10);
D. let mut pq = std::collections::BinaryHeap::new();

Solution

  1. Step 1: Recall Rust BinaryHeap creation

    The standard way to create a max-heap priority queue is using BinaryHeap::new().
  2. Step 2: Check other options

    with_capacity(10i32) type mismatch (usize expected); default(10) invalid arguments; min_heap() does not exist.
  3. Final Answer:

    let mut pq = std::collections::BinaryHeap::new(); -> Option D
  4. Quick Check:

    BinaryHeap::new() creates max-heap [OK]
Hint: Use BinaryHeap::new() for max-heap priority queue [OK]
Common Mistakes:
  • Using with_capacity with i32 instead of usize
  • Passing arguments to default()
  • Using non-existent min_heap() method
3. What will be the output of the following Rust code using a priority queue?
use std::collections::BinaryHeap;

fn main() {
    let mut pq = BinaryHeap::new();
    pq.push(10);
    pq.push(5);
    pq.push(20);
    while let Some(val) = pq.pop() {
        print!("{} ", val);
    }
}
medium
A. 20 10 5
B. 5 20 10
C. 10 5 20
D. 5 10 20

Solution

  1. Step 1: Understand BinaryHeap behavior

    Rust's BinaryHeap is a max-heap by default, so pop() returns the largest element first.
  2. Step 2: Trace the pop order

    Inserted values: 10, 5, 20. Popping returns 20, then 10, then 5.
  3. Final Answer:

    20 10 5 -> Option A
  4. Quick Check:

    Max-heap pop order = descending [OK]
Hint: BinaryHeap pops largest first, so output is descending [OK]
Common Mistakes:
  • Assuming pop returns elements in insertion order
  • Thinking BinaryHeap is min-heap by default
  • Mixing up push and pop order
4. Identify the error in this Rust code that tries to create a min-heap priority queue:
use std::collections::BinaryHeap;

fn main() {
    let mut pq = BinaryHeap::new();
    pq.push(3);
    pq.push(1);
    pq.push(2);
    while let Some(val) = pq.pop() {
        println!("{}", val);
    }
}
medium
A. BinaryHeap does not support min-heap by default
B. pq.push() method does not exist
C. pop() returns elements in insertion order
D. println! macro is used incorrectly

Solution

  1. Step 1: Check BinaryHeap default behavior

    Rust's BinaryHeap is a max-heap by default, so it does not create a min-heap without extra work.
  2. Step 2: Verify code correctness

    push() and pop() methods exist and println! is correct; the issue is the heap type.
  3. Final Answer:

    BinaryHeap does not support min-heap by default -> Option A
  4. Quick Check:

    BinaryHeap default = max-heap, no min-heap [OK]
Hint: BinaryHeap is max-heap by default; min-heap needs wrapper [OK]
Common Mistakes:
  • Assuming BinaryHeap is min-heap by default
  • Thinking push() or pop() are missing
  • Misreading println! syntax
5. You want to implement a task scheduler in Rust that always runs the highest priority task first. Which approach correctly uses a priority queue to achieve this?
use std::collections::BinaryHeap;

struct Task {
    priority: i32,
    name: String,
}

fn main() {
    let mut pq = BinaryHeap::new();
    pq.push(Task { priority: 2, name: String::from("Clean") });
    pq.push(Task { priority: 5, name: String::from("Cook") });
    pq.push(Task { priority: 1, name: String::from("Shop") });

    while let Some(task) = pq.pop() {
        println!("{}", task.name);
    }
}

What must you do to make this code work as intended?
hard
A. Use a Vec<Task> instead of BinaryHeap
B. Implement Ord and Eq traits for Task to order by priority
C. Change priority to u32 type
D. Replace pop() with peek() in the loop

Solution

  1. Step 1: Understand BinaryHeap requirements

    BinaryHeap requires elements to implement Ord and Eq to compare and order them.
  2. Step 2: Check code for ordering

    Task struct has no ordering traits implemented, so BinaryHeap cannot order tasks by priority.
  3. Step 3: Correct approach

    Implement Ord and Eq for Task to order by priority, so highest priority pops first.
  4. Final Answer:

    Implement Ord and Eq traits for Task to order by priority -> Option B
  5. Quick Check:

    BinaryHeap needs Ord/Eq for custom types [OK]
Hint: Custom types need Ord/Eq traits for BinaryHeap ordering [OK]
Common Mistakes:
  • Using Vec instead of priority queue
  • Changing data type without ordering
  • Using peek() instead of pop() to remove elements
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard