C# PriorityQueue
last modified October 5, 2026
C# PriorityQueue tutorial shows how to use the
PriorityQueue<TElement, TPriority> collection in .NET.
A priority queue stores elements together with priorities. Unlike a regular
queue, which removes elements in the order they were added, a priority queue
removes an element with the smallest priority first by default. The collection
is part of System.Collections.Generic and is available starting
with .NET 6.
The .NET priority queue is implemented as a quaternary min-heap. It does not keep all elements in sorted order; it organizes them so that the element with the minimum priority can be found efficiently.
C# PriorityQueue example
In the first example, we enqueue jobs with integer priorities and process them from the smallest priority value to the largest.
using System;
using System.Collections.Generic;
var jobs = new PriorityQueue<string, int>();
jobs.Enqueue("Generate monthly report", 3);
jobs.Enqueue("Process payment", 2);
jobs.Enqueue("Database alert", 1);
while (jobs.TryDequeue(out var job, out var priority))
{
Console.WriteLine($"{priority}: {job}");
}
The first generic type is the element type, and the second is the priority
type. Each call to Enqueue supplies both values.
var jobs = new PriorityQueue<string, int>();
We create a queue of string jobs whose priorities are integers. The default priority comparer orders integers in ascending order, so a smaller number means that a job is processed sooner.
while (jobs.TryDequeue(out var job, out var priority))
TryDequeue removes the element with the smallest priority and
returns both the element and its priority. It returns false when
the queue is empty, so the loop ends without an exception.
$ dotnet run 1: Database alert 2: Process payment 3: Generate monthly report
C# PriorityQueue operations
Peek reads the element with the smallest priority without removing
it. TryPeek is useful when the queue might be empty.
Dequeue removes and returns the minimum-priority element, and
Count gives the number of queued elements.
using System;
using System.Collections.Generic;
var queue = new PriorityQueue<string, int>();
queue.Enqueue("Write tests", 2);
queue.Enqueue("Fix production issue", 1);
Console.WriteLine($"Next: {queue.Peek()}");
Console.WriteLine($"Queued: {queue.Count}");
if (queue.TryDequeue(out var task, out var priority))
{
Console.WriteLine($"Started {task} (priority {priority})");
}
Console.WriteLine($"Remaining: {queue.Count}");
Peek leaves the queue unchanged. If an empty queue is possible,
use TryPeek or TryDequeue instead of
Peek or Dequeue; the non-try methods throw
InvalidOperationException when no element is available.
$ dotnet run Next: Fix production issue Queued: 2 Started Fix production issue (priority 1) Remaining: 1
C# PriorityQueue with a custom comparer
The default comparer makes a min-priority queue: lower values come out first.
Pass an IComparer<TPriority> to the constructor to change
that order. This example uses a comparer that puts larger numbers first.
using System;
using System.Collections.Generic;
var comparer = Comparer<int>.Create((left, right) => right.CompareTo(left));
var scores = new PriorityQueue<string, int>(comparer);
scores.Enqueue("Ada", 84);
scores.Enqueue("Linus", 97);
scores.Enqueue("Grace", 91);
while (scores.TryDequeue(out var name, out var score))
{
Console.WriteLine($"{score}: {name}");
}
The comparer reverses the usual integer order. Consequently, the queue now removes the entry with the highest score first.
$ dotnet run 97: Linus 91: Grace 84: Ada
Equal priorities and stable ordering
The queue does not guarantee first-in, first-out ordering for elements with equal priorities. If equal-priority items must retain their insertion order, include a sequence number as a secondary part of the priority.
using System;
using System.Collections.Generic;
var tasks = new PriorityQueue<string, (int Rank, long Sequence)>();
long sequence = 0;
tasks.Enqueue("First normal task", (2, sequence++));
tasks.Enqueue("Urgent task", (1, sequence++));
tasks.Enqueue("Second normal task", (2, sequence++));
while (tasks.TryDequeue(out var task, out var priority))
{
Console.WriteLine($"rank {priority.Rank}: {task}");
}
Value tuples are compared field by field. The rank is considered first, then the sequence number breaks ties, so tasks at the same rank are processed in the order they were enqueued.
$ dotnet run rank 1: Urgent task rank 2: First normal task rank 2: Second normal task
C# PriorityQueue details
The priority type does not have to be numeric. It can be any type that can be ordered by the default comparer, or by a comparer supplied to the constructor. For example, a date can be used to process the nearest deadline first.
Enqueueadds an element and its priority in logarithmic time.DequeueandTryDequeueremove the minimum-priority element in logarithmic time.PeekandTryPeekinspect the minimum-priority element in constant time.UnorderedItemsexposes the queued element-priority pairs, but their enumeration is not sorted by priority.
The queue is not synchronized for concurrent access. If multiple threads need to modify the same instance, protect those operations with suitable synchronization or use a concurrent design.
Source
PriorityQueue<TElement, TPriority> Class - Microsoft Learn
In this article we have worked with the PriorityQueue<TElement, TPriority>
collection in C#.
Author
List all C# tutorials.