JavaScript
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax and Types
-
Section 3: Strings and Numbers in Depth
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Objects and Arrays
-
Section 7: Maps, Sets, and Symbols
-
Section 8: Asynchronous JavaScript
-
Section 9: Object-Oriented and Prototypes
-
Section 10: The DOM
-
Section 11: Browser APIs
-
Section 12: Modern JavaScript (ES2015-ES2025)
-
Section 13: Functional Programming Patterns
-
Section 14: Error Handling and Debugging
-
Section 15: Testing
-
Section 16: Accessibility for JavaScript Developers
-
Section 17: Internationalization and Localization
-
Section 18: Performance
-
Section 19: Node.js Fundamentals
-
Section 20: Regular Expressions
-
Section 21: Design Patterns in JavaScript
-
Section 22: Security Basics
-
Section 23: Data Structures and Algorithms in JavaScript
-
Section 24: Practical Projects
-
Section 25: More Advanced Async Patterns
-
Section 26: More Object and Class Practice
-
Section 27: Working with Dates and Internationalization
-
Section 28: Web Components
-
Section 29: More DOM and Browser Practice
-
Section 30: Build Tooling for Vanilla JavaScript
-
Section 31: More Practice Projects
-
Section 32: Interview and Algorithm Practice
-
Section 33: Error Objects (MDN Reference)
-
Section 34: TypedArrays and Binary Data
-
Section 35: Reflection and Metaprogramming (MDN Reference)
-
Section 36: More Global Functions (MDN Reference)
175: Implementing a Min-Heap
Think about a hospital's emergency room triage. Patients don't just get seen in the order they arrive; they get seen based on the severity of their condition. If someone comes in with a minor scrape, they wait. If someone comes in with a heart attack, they jump to the front of the line immediately. A Min-Heap is essentially a triage system for data. It ensures that the "most urgent" (the smallest) value is always sitting right at the top, ready to be grabbed, regardless of when it was added to the pile.
Here is how that maps to the logic we're about to write:
- The Patient: This is the value you're inserting into the heap.
- Triage Priority: In a Min-Heap, the smaller the number, the higher the priority.
- The Waiting Room: We use an array to represent a binary tree. It's a bit of a mental leap, but it's much faster than creating actual "Node" objects with left and right pointers.
- Moving Up the Line: When a critical patient arrives, they "bubble up" through the queue until they are in the right spot relative to others.
- Filling the Gap: When the doctor takes the most urgent patient, someone else has to step up, and we "bubble down" to make sure the next most urgent person is now at the front.
Flattening a Tree into an Array
I know it sounds weird to store a tree in a flat array, but this is the "secret sauce" of heaps. Since a heap is always a complete binary tree, we don't need pointers. We can use simple math to find relatives. If you're at index i:
- Your left child is at
2i + 1. - Your right child is at
2i + 2. - Your parent is at
Math.floor((i - 1) / 2).
I've spent hours debugging off-by-one errors in the past because I forgot these formulas. Memorize them, or keep them on a sticky note; they are the foundation of the whole structure.
Keeping the Peace: Bubbling Up and Down
The core of a Min-Heap is maintaining the "Heap Property": every parent must be smaller than its children. When we break that rule—either by adding a new element or removing the root—we have to fix it.
class MinHeap {
constructor() {
this.heap = [];
}
insert(val) {
this.heap.push(val);
this.bubbleUp(this.heap.length - 1);
}
bubbleUp(index) {
while (index > 0) {
let parentIndex = Math.floor((index - 1) / 2);
if (this.heap[parentIndex] <= this.heap[index]) break;
// Swap parent and child
[this.heap[parentIndex], this.heap[index]] = [this.heap[index], this.heap[parentIndex]];
index = parentIndex;
}
}
extractMin() {
if (this.heap.length === 0) return null;
if (this.heap.length === 1) return this.heap.pop();
const min = this.heap[0];
// Move the last element to the top and bubble it down
this.heap[0] = this.heap.pop();
this.bubbleDown(0);
return min;
}
bubbleDown(index) {
while (true) {
let left = 2 * index + 1;
let right = 2 * index + 2;
let smallest = index;
if (left < this.heap.length && this.heap[left] < this.heap[smallest]) {
smallest = left;
}
if (right < this.heap.length && this.heap[right] < this.heap[smallest]) {
smallest = right;
}
if (smallest === index) break;
[this.heap[index], this.heap[smallest]] = [this.heap[smallest], this.heap[index]];
index = smallest;
}
}
}
Notice in extractMin how I don't just shift the whole array. Shifting an array is an O(n) operation, which would kill the performance of our heap. Instead, I take the very last element—the one that's least likely to be the minimum—and throw it at the top. It'll probably be way too large for that spot, but bubbleDown will efficiently sink it to its rightful place in O(log n) time.
📋 Practical Task
Build a Priority-Based Task Scheduler
You need to build a TaskScheduler class that uses the MinHeap implementation from the lesson. Instead of just storing numbers, your heap should store "Task" objects. Each task has a priority (lower number = higher priority) and a description.
Requirements:
- Modify the
MinHeaplogic to compare thepriorityproperty of the objects rather than the objects themselves. - Implement a
addTask(description, priority)method. - Implement a
processNextTask()method that extracts and returns the task with the highest priority (the lowest priority number). - Test your scheduler by adding tasks in this order:
- "Fix CSS bug" (Priority 3)
- "Server crash" (Priority 1)
- "Update documentation" (Priority 5)
- "Security patch" (Priority 2)
- Verify that calling
processNextTask()four times returns the tasks in the order: Server crash, Security patch, Fix CSS bug, Update documentation.
There are no comments for now.