typescript
54 lines · 9 steps
Building a binary-heap priority queue in TypeScript
A generic min-heap that keeps the lowest-priority item ready at the front through bubble-up and bubble-down.
Explained by
highlit
1export class PriorityQueue<T> {
2 private heap: Array<{ value: T; priority: number }> = [];
3
4 get size(): number {
5 return this.heap.length;
6 }
7
8 peek(): T | undefined {
9 return this.heap[0]?.value;
10 }
11
12 enqueue(value: T, priority: number): void {
13 this.heap.push({ value, priority });
14 this.bubbleUp(this.heap.length - 1);
15 }
16
17 dequeue(): T | undefined {
18 if (this.heap.length === 0) return undefined;
19 const top = this.heap[0];
20 const last = this.heap.pop()!;
21 if (this.heap.length > 0) {
22 this.heap[0] = last;
23 this.bubbleDown(0);
24 }
25 return top.value;
26 }
27
28 private bubbleUp(index: number): void {
29 while (index > 0) {
30 const parent = (index - 1) >> 1;
31 if (this.heap[index].priority >= this.heap[parent].priority) break;
32 this.swap(index, parent);
33 index = parent;
34 }
35 }
36
37 private bubbleDown(index: number): void {
38 const n = this.heap.length;
39 while (true) {
40 const left = index * 2 + 1;
41 const right = left + 1;
42 let smallest = index;
43 if (left < n && this.heap[left].priority < this.heap[smallest].priority) smallest = left;
44 if (right < n && this.heap[right].priority < this.heap[smallest].priority) smallest = right;
45 if (smallest === index) break;
46 this.swap(index, smallest);
47 index = smallest;
48 }
49 }
50
51 private swap(a: number, b: number): void {
52 [this.heap[a], this.heap[b]] = [this.heap[b], this.heap[a]];
53 }
54}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1A binary heap stores a tree in a flat array, using index arithmetic to find parents and children.
- 2Insertion and removal both cost O(log n) because an item only travels the height of the tree.
- 3Sifting up on enqueue and down on dequeue is what preserves the heap ordering invariant.
Related explainers
typescript
import { useState, useEffect, useRef, useCallback } from "react"; interface Suggestion { id: string;
A debounced autocomplete hook in React
debounce
custom-hooks
abortcontroller
Advanced
7 steps
rust
use axum::body::Bytes; use axum::http::{header, HeaderValue, StatusCode}; use axum::response::{IntoResponse, Response}; use serde::Serialize;
Custom Axum responses with per-user ETags
etag
trait-implementation
generics
Intermediate
7 steps
typescript
import { Body, Controller, Ip, Post, UnauthorizedException } from '@nestjs/common'; import { Throttle, ThrottlerGuard } from '@nestjs/throttler'; import { UseGuards } from '@nestjs/common'; import { AuthService } from './auth.service';
Rate-limiting an auth flow in NestJS
rate-limiting
authentication
guards
Intermediate
8 steps
typescript
import { Component, computed, DestroyRef, inject, input, output, signal } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { interval, map, takeWhile } from 'rxjs';
How a signal-driven countdown works in Angular
signals
reactivity
rxjs
Intermediate
8 steps
typescript
type TokenType = "keyword" | "string" | "comment" | "number" | "text"; interface Token { type: TokenType;
How a regex tokenizer highlights code
tokenizer
regex
lexing
Intermediate
10 steps
typescript
import { Component, inject, signal } from '@angular/core'; import { CdkDragDrop, DragDropModule, moveItemInArray } from '@angular/cdk/drag-drop'; import { HttpClient } from '@angular/common/http'; import { finalize } from 'rxjs';
Drag-and-drop reordering with signals in Angular
drag-and-drop
signals
optimistic-update
Intermediate
8 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/building-a-binary-heap-priority-queue-in-typescript-explained-typescript-8d7b/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.