NeetCode - realestateexplorer/SystemDesign GitHub Wiki
explain priority queue, enqueue and dequeue in c#
Of course! Let's break down the Priority Queue concept and its key operations, Enqueue
and Dequeue
, specifically in the context of C#.
1. The Concept: What is a Priority Queue?
A Priority Queue is a special type of queue where each item has an associated "priority." Unlike a regular queue which operates on a "First-In, First-Out" (FIFO) basis, a priority queue dequeues items in order of their priority.
Think of an emergency room triage system:
- Regular Queue (like a deli counter): The first person to arrive is the first person served.
- Priority Queue (like an ER): A patient with a critical gunshot wound (high priority) will be seen before someone with a sprained ankle (low priority), even if the ankle sprain patient arrived first.
The item with the highest priority is always removed first.
Key Point in C#: The built-in PriorityQueue<TElement, TPriority>
class in C# is a Min-Priority Queue. This means the item with the lowest priority value is considered the highest priority and will be dequeued first.
- Priority
1
comes out before priority5
. - Priority
10
comes out before priority100
.
PriorityQueue<TElement, TPriority>
2. The C# Implementation: Starting with .NET 6, C# has a built-in, highly optimized PriorityQueue
class in the System.Collections.Generic
namespace.
It is defined as PriorityQueue<TElement, TPriority>
, where:
TElement
: The type of the item you want to store (e.g., astring
for a task name, a customPatient
object).TPriority
: The type of the priority value, which must be comparable (e.g.,int
,double
,DateTime
).
// We will store strings (task names) with integer priorities.
// Lower integer means higher priority.
var taskQueue = new PriorityQueue<string, int>();
Enqueue
Operation
3. The Purpose: To add a new item (an element and its priority) to the queue.
When you Enqueue
an item, it isn't just added to the end. The Priority Queue internally reorganizes itself (typically using a data structure called a binary heap) to ensure that the item with the highest priority (lowest priority value) is ready to be accessed quickly.
How to use it: You call the .Enqueue()
method, providing both the element and its priority.
Syntax: queue.Enqueue(TElement element, TPriority priority);
Enqueue Example:
Let's add some tasks to our queue in a non-sequential order of priority.
using System.Collections.Generic;
var taskQueue = new PriorityQueue<string, int>();
Console.WriteLine("Enqueuing tasks...");
// Enqueue tasks with their priorities (1 = highest priority)
taskQueue.Enqueue("Fix critical bug", 1);
taskQueue.Enqueue("Write documentation", 5);
taskQueue.Enqueue("Deploy to production", 2);
taskQueue.Enqueue("Add new feature", 3);
// At this point, the queue knows that "Fix critical bug" has the highest priority.
Console.WriteLine($"Number of tasks in queue: {taskQueue.Count}"); // Output: 4
Dequeue
Operation
4. The Purpose: To remove the item with the highest priority from the queue and return it.
In C#'s Min-Priority Queue
, Dequeue
will always remove and return the element that has the lowest priority value.
Important: If you call Dequeue()
on an empty queue, it will throw an InvalidOperationException
. It's often safer to check queue.Count > 0
or use the TryDequeue()
method.
Syntax: TElement element = queue.Dequeue();
Dequeue Example:
Continuing from the previous example, let's process the tasks. Notice how they come out in priority order, not the order they were added.
Console.WriteLine("\nProcessing tasks by priority...");
// Process tasks until the queue is empty
while (taskQueue.Count > 0)
{
// Dequeue the highest-priority task
string task = taskQueue.Dequeue();
Console.WriteLine($"Processing: {task}");
}
Expected Output:
Enqueuing tasks...
Number of tasks in queue: 4
Processing tasks by priority...
Processing: Fix critical bug
Processing: Deploy to production
Processing: Add new feature
Processing: Write documentation
Putting It All Together: A Complete Example
This example demonstrates Enqueue
, Dequeue
, and the safer TryDequeue
method.
using System;
using System.Collections.Generic;
// Let's model a hospital emergency room
public class Patient
{
public string Name { get; set; }
public Patient(string name) => Name = name;
}
public class PriorityQueueExample
{
public static void Main(string[] args)
{
// TElement is Patient, TPriority is int
// Priority 1: Critical, 2: Urgent, 3: Stable
var erQueue = new PriorityQueue<Patient, int>();
// Patients arrive in a random order
Console.WriteLine("--- Patients Arriving ---");
erQueue.Enqueue(new Patient("John (Broken Arm)"), 3);
Console.WriteLine("Enqueued: John (Broken Arm), Priority 3");
erQueue.Enqueue(new Patient("Alice (Chest Pains)"), 1);
Console.WriteLine("Enqueued: Alice (Chest Pains), Priority 1");
erQueue.Enqueue(new Patient("Bob (High Fever)"), 2);
Console.WriteLine("Enqueued: Bob (High Fever), Priority 2");
Console.WriteLine($"\nTotal patients in queue: {erQueue.Count}");
Console.WriteLine("\n--- Doctors Treating Patients ---");
// Use TryDequeue in a loop for safe processing
while (erQueue.TryDequeue(out Patient patient, out int priority))
{
Console.WriteLine($"Treating patient: {patient.Name} with priority: {priority}");
}
Console.WriteLine($"\nPatients remaining in queue: {erQueue.Count}");
}
}
Output of the Complete Example:
--- Patients Arriving ---
Enqueued: John (Broken Arm), Priority 3
Enqueued: Alice (Chest Pains), Priority 1
Enqueued: Bob (High Fever), Priority 2
Total patients in queue: 3
--- Doctors Treating Patients ---
Treating patient: Alice (Chest Pains) with priority: 1
Treating patient: Bob (High Fever) with priority: 2
Treating patient: John (Broken Arm) with priority: 3
Patients remaining in queue: 0
This output perfectly illustrates the core principle: despite arriving second, Alice was treated first because her priority value (1
) was the lowest (i.e., the highest priority).