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
1comes out before priority5. - Priority
10comes out before priority100.
2. The C# Implementation: PriorityQueue<TElement, TPriority>
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., astringfor a task name, a customPatientobject).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>();
3. The Enqueue Operation
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
4. The Dequeue Operation
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).