A collection of JavaScript implementations of common algorithms and data structures. This repository includes sorting algorithms, search algorithms, data structures (trees, linked lists, heaps, queues), and various utility functions for learning and reference.
- Anagram Checker
- Binary Heaps
- Binary Search Tree
- Binary Search
- Cash Register
- Collect Odd Values
- Collect Strings
- Decimals Fix
- Doubly Linked List
- Factorial
- Fibonacci
- Fix Runts
- Graphs
- Merge Sort
- Palindrome Checker
- Priority Queue
- Quick Sort
- Radix Sort
- Roman Numeral Converter
- ROT13
- Segment Image
- Shortest Path (Dijkstra's Algorithm)
- Singly Linked List
- Stacks & Queues
- Telephone Checker
- Title Case
- Tree Traversal
Checks if two strings are anagrams of each other. An anagram is a word or phrase formed by rearranging the letters of another word or phrase, using all the original letters exactly once. The areAnagrams function performs a case-insensitive comparison by counting character frequencies in both strings.
The algorithm works by:
- First checking if the strings have different lengths (quick exit if true)
- Converting both strings to lowercase for case-insensitive comparison
- Building a character frequency map for the first string
- Decrementing counts while iterating through the second string
- Verifying all counts are zero at the end
console.log(areAnagrams('cat', 'tac')); // Output: true
console.log(areAnagrams('listen', 'silent')); // Output: true
console.log(areAnagrams('hello', 'world')); // Output: false
console.log(areAnagrams('Dormitory', 'Dirty room')); // Output: false (spaces matter)Implementation of a binary heap data structure, which is a complete binary tree where each parent node is either greater than or equal to (max heap) or less than or equal to (min heap) its child nodes. Commonly used for priority queues and heap sort algorithms.
A binary search tree (BST) implementation where each node has at most two children, and for each node, all values in the left subtree are less than the node's value, and all values in the right subtree are greater. Provides efficient searching, insertion, and deletion operations.
An efficient algorithm for finding a target value within a sorted array. Works by repeatedly dividing the search interval in half, comparing the target value to the middle element, and eliminating half of the remaining elements.
console.log(binarySearch([1, 2, 3, 4, 5, 6, 7, 8, 9], 5));
// Output: 4 (index of the value)
A complete cash register system that manages transactions, calculates change, and tracks drawer contents. The CashRegister class uses a greedy algorithm to provide change using the largest denominations first, and handles all calculations in cents to avoid floating-point errors.
Features:
- Transaction Processing: Validates payment, calculates change, and updates drawer
- Change Calculation: Uses greedy algorithm considering both drawer contents and paid funds
- Error Handling: Detects insufficient payment or inability to make proper change
- Precision: All calculations done in cents to avoid floating-point issues
- Flexible Denominations: Supports bills and coins (5000, 2000, 1000, 500, 200, 100, 50, 20, 10, 5, 2, 1, 0.5, 0.2, 0.1, 0.05, 0.01)
Implementation Details:
The class uses private methods for internal operations:
#addToDrawer(): Adds denominations to the drawer#removeFromDrawer(): Removes denominations from the drawer#convertToCents(): Converts dollar amounts to cents for precise calculations#makeChange(): Calculates optimal change using greedy algorithm, considering both existing drawer contents and newly paid funds#makePayment(): Adds customer payment to the drawer
Public Methods:
processTransaction(price, paidFunds): Process a sale and return changegetDrawerContents(): Get current denominations in drawergetTotal(): Get total cash value in drawer
const cashRegister = new CashRegister({
100: 5, // 5 x $100 bills
50: 10, // 10 x $50 bills
20: 20, // 20 x $20 bills
10: 15,
5: 20,
1: 50,
0.5: 10, // 10 x 50¢ coins
0.25: 20, // 20 x 25¢ coins
0.1: 50, // 50 x 10¢ coins
0.01: 100, // 100 x 1¢ coins
});
// Process a transaction
cashRegister.processTransaction(3, { 1: 5 });
// Calculates change of $2 and updates drawer
// Exact payment
const result = cashRegister.processTransaction(20, { 20: 1 });
console.log(result);
// Output: "Exact! Here you go."
// Check drawer contents and total
const contents = cashRegister.getDrawerContents();
console.log(contents); // { 100: 5, 50: 10, ... }
const total = cashRegister.getTotal();
console.log(total); // 1234.56 (example total in dollars)A recursive function that collects all odd values from an array of numbers.
Three different implementations for collecting all string values from a nested object. Each demonstrates a different traversal approach:
collectStringsIterative(obj) - Uses an iterative approach with a stack to traverse the object tree depth-first. This avoids recursion and potential stack overflow issues with deeply nested objects, making it suitable for large or deeply nested data structures.
collectStringsRecursiveHelper(obj) - Uses recursion with a helper function pattern. The outer function creates a result array in its scope, and an inner helper function recursively traverses the object, accumulating strings in the shared result array.
collectStringsRecursivePure(obj) - Uses pure recursion without helper functions. Each recursive call is self-contained, concatenating results from nested calls. This is a "pure" functional approach where each function call doesn't rely on outer scope variables.
const obj = {
stuff: 'foo',
data: {
val: {
thing: {
info: 'bar',
moreInfo: {
evenMoreInfo: {
weMadeIt: 'baz',
},
},
},
},
},
};
console.log(collectStringsIterative(obj));
// Output: ["foo", "bar", "baz"]
console.log(collectStringsRecursiveHelper(obj));
// Output: ["foo", "bar", "baz"]
console.log(collectStringsRecursivePure(obj));
// Output: ["foo", "bar", "baz"]Decimals fix overcomes Javascript floating-point rounding errors issues when trying to add or subtract two numbers with decimal spaces. For example, 0.1 + 0.2 === 0.30000000000000004. This happens because all javascript numbers are double-precision floating-point, so to fix this we have to determine how many decimals spaces there are, multiply to convert numbers to integers, perform addition or subtraction, and then divide again to get the decimal point.
let a = 0.1;
let b = 0.2;
let maxDecimals = getMaxDecimalDivider(1, Math.max(countDecimalSpaces(a), countDecimalSpaces(b)));
console.log(a + b);
// Output: 0.30000000000000004
console.log((convertDecimalsToInteger(a, 1, maxDecimals) + convertDecimalsToInteger(b, 1, maxDecimals)) / maxDecimals);
// Output: 0.3
Implementation of a doubly linked list data structure where each node contains a reference to both the next and previous nodes in the sequence. This allows for efficient bidirectional traversal and insertion/deletion operations at both ends.
Factorial is a function that calculates the factorial from a given number that is passed as a parameter.
console.log(factorial(10));
// Output: 3628800
Two implementations for calculating the nth Fibonacci number. The Fibonacci sequence is a series where each number is the sum of the two preceding ones, starting from 1 and 1. The sequence goes: 1, 1, 2, 3, 5, 8, 13, 21, 34, ...
fibRecursive(n) - Uses recursive approach with memoization (caching previously calculated values in a Map) to avoid redundant calculations. This makes it significantly faster than naive recursion while maintaining an elegant recursive structure. Time complexity: O(n), Space complexity: O(n)
fibTabulation(n) - Uses dynamic programming tabulation (bottom-up approach) to build the Fibonacci sequence iteratively. This approach is typically faster than the recursive memoized version for larger values as it avoids function call overhead. Time complexity: O(n), Space complexity: O(n)
// Recursive with memoization
console.log(fibRecursive(1)); // Output: 1
console.log(fibRecursive(2)); // Output: 1
console.log(fibRecursive(5)); // Output: 5
console.log(fibRecursive(10)); // Output: 55
console.log(fibRecursive(50)); // Output: 12586269025
// Tabulation (bottom-up)
console.log(fibTabulation(1)); // Output: 1
console.log(fibTabulation(2)); // Output: 1
console.log(fibTabulation(5)); // Output: 5
console.log(fibTabulation(10)); // Output: 55
console.log(fibTabulation(100)); // Output: 354224848179262000000Function that fixes runts from the string (paragraph). It replaces the last whitespace character with the (non-breaking space character)
let str = "640K ought to be enough for anybody. (Bill Gates, 1981) The best thing about a boolean is even if you are wrong, you are only off by a bit. (Anonymous) I think Microsoft named .Net so it wouldn't show up in a Unix directory listing. (Oktal) Come to think of it, there are already a million monkeys on a million typewriters, and Usenet is nothing like Shakespeare. (Blair Houghton)"
console.log(fixRunts(str))
// Output: 640K ought to be enough for anybody. (Bill Gates, 1981) The best thing about a boolean is even if you are wrong, you are only off by a bit. (Anonymous) I think Microsoft named .Net so it wouldn't show up in a Unix directory listing. (Oktal) Come to think of it, there are already a million monkeys on a million typewriters, and Usenet is nothing like Shakespeare. (Blair Houghton)
Implementation of an undirected graph data structure using an adjacency list representation. Includes methods for adding/removing vertices and edges, as well as traversal algorithms:
- Depth-First Search (Recursive): Explores as far as possible along each branch before backtracking
- Depth-First Search (Iterative): Uses a stack to traverse the graph depth-first
- Breadth-First Search: Uses a queue to visit nodes level by level
Graphs are fundamental data structures used to represent networks, relationships, and connections between entities.
A divide-and-conquer sorting algorithm that divides the input array into two halves, recursively sorts them, and then merges the sorted halves. Has a time complexity of O(n log n) and is stable.
Checks if a string is a palindrome (reads the same forwards and backwards). A palindrome is a word or sentence that's spelled the same way both forward and backward, ignoring punctuation, case, and spacing.
The isPalindrome function extracts only alphabetic characters using regex, converts them to lowercase, and then iterates through the string comparing characters from both ends moving toward the center. If any characters don't match, it returns false; otherwise, it returns true.
console.log(isPalindrome('awesome')); // Output: false
console.log(isPalindrome('foobar')); // Output: false
console.log(isPalindrome('eye')); // Output: true
console.log(isPalindrome('A man, a plan, a canal: Panama')); // Output: true
console.log(isPalindrome('race car')); // Output: trueA priority queue implementation using a binary heap where elements are served based on their priority rather than their order in the queue. Higher priority elements are dequeued before lower priority elements.
An efficient divide-and-conquer sorting algorithm that works by selecting a 'pivot' element and partitioning the array around it, such that elements smaller than the pivot come before it and elements greater come after. Has an average time complexity of O(n log n).
A non-comparative sorting algorithm that sorts integers by processing individual digits. It groups numbers by each digit position and is particularly efficient for sorting large sets of integers.
Converts the Arabic numbers to roman and vice versa. For converting from Arabic to roman use function convertToRoman(num) with the number as a parameter and for converting from roman to Arabic use function convertToArabic(str) with the string as a parameter that is passed to the function. Both functions return a number or a letter, depending on which function you use.
console.log(convertToRoman(3999));
// Output: MMMCMXCIX
console.log(convertToArabic("MMMCMXCIX"));
// Output: 3999
A simple letter substitution cipher that replaces a letter with the letter 13 positions after it in the alphabet. ROT13 is a special case of the Caesar cipher and is its own inverse (applying ROT13 twice returns the original text).
console.log(rot13("SERR PBQR PNZC"));
// Output: FREE CODE CAMP
Segments a 2D image array by finding all connected regions of a specific value using Breadth-First Search (BFS). This algorithm identifies connected components in a grid where cells are considered connected if they share an edge (4-directional connectivity: up, down, left, right).
The segmentByValue function takes a 2D array and a target value, then returns all segments where each segment is a group of connected cells with that value. This is useful for image processing tasks like blob detection, region labeling, and pattern recognition.
const img = [
[0, 1, 0],
[0, 1, 1],
[1, 0, 0]
];
const segments = segmentByValue(img, 1); // Find all segments of 1s
console.log(segments);
// Output: [[[0,1], [1,1], [1,2]], [[2,0]]]
// Two separate segments: one with three connected 1s, one with a single 1
const zeroSegments = segmentByValue(img, 0); // Find all segments of 0s
console.log(zeroSegments);
// Output: [[[0,0], [1,0]], [[0,2], [1,2], [2,1], [2,2]]]
Implementation of Dijkstra's algorithm for finding the shortest path between nodes in a weighted graph. Uses a priority queue (min-heap) to efficiently select the next node with the smallest distance. The algorithm:
- Initializes distances from the start node (0 for start, Infinity for others)
- Uses a priority queue to process nodes in order of their distance
- For each node, updates distances to neighbors if a shorter path is found
- Tracks the previous node in each shortest path to reconstruct the final route
Returns an array representing the shortest path from the start to the end node. Essential for navigation systems, network routing, and optimization problems.
Implementation of a singly linked list data structure where each node contains data and a reference to the next node in the sequence. Provides efficient insertion and deletion at the beginning, but requires traversal for accessing elements.
Implementation of stack (Last-In-First-Out) and queue (First-In-First-Out) data structures. Stacks support push and pop operations, while queues support enqueue and dequeue operations.
Checks if a telephone number is in valid format. The parameter that is passed to the function is a string and the function returns a boolean as a result.
console.log(telephoneCheck("1 555)555-5555"));
// Output: false
console.log(telephoneCheck("1 555-555-5555"));
// Output: true
The function that converts the string that is passed as a parameter to the title case.
let str = 'title case here';
console.log(titleCase(str));
// Output: Title Case Here
Implementation of various tree traversal algorithms including:
- Breadth-First Search (BFS): Visits nodes level by level
- Depth-First Search (DFS): Includes Pre-order, In-order, and Post-order traversals
These algorithms are fundamental for navigating and processing tree data structures.
Checks if a word or a sentence is a palindrome. A palindrome is a word or a sentence that's spelled the same way both forward and backward, ignoring the punctuation, case, and spacing. The function works by removing all non-alphanumeric characters (punctuation, spaces, and symbols) and turns everything into the same case (lower or upper case) to check for palindromes. The result of the function is a boolean (true or false) and it depends if the palindrome is found or not.
console.log(palindrome("1 eye for of 1 eye."));
// Output: true
Factorial is a function that calculates the factorial from a given number that is passed as a parameter.
console.log(factorial(10));
// Output: 3628800
Checks if a telephone number is in valid format. The parameter that is passed to the function is a string and the function returns a boolean as a result.
console.log(telephoneCheck("1 555)555-5555"));
// Output: false
console.log(telephoneCheck("1 555-555-5555"));
// Output: true
Decimals fix overcomes Javascript floating-point rounding errors issues when trying to add or subtract two numbers with decimal spaces. For example, 0.1 + 0.2 === 0.30000000000000004. This happens because all javascript numbers are double-precision floating-point, so to fix this we have to determine how many decimals spaces there are, multiply to convert numbers to integers, perform addition or subtraction, and then divide again to get the decimal point.
let a = 0.1;
let b = 0.2;
let maxDecimals = getMaxDecimalDivider(1, Math.max(countDecimalSpaces(a), countDecimalSpaces(b)));
console.log(a + b);
// Output: 0.30000000000000004
console.log((convertDecimalsToInteger(a, 1, maxDecimals) + convertDecimalsToInteger(b, 1, maxDecimals)) / maxDecimals);
// Output: 0.3
The function that converts the string that is passed as a parameter to the title case.
let str = 'title case here';
console.log(titleCase(str));
// Output: Title Case Here
Function that fixes runts from the string (paragraph). It replaces the last whitespace character with the (non-breaking space character)
let str = "640K ought to be enough for anybody. (Bill Gates, 1981) The best thing about a boolean is even if you are wrong, you are only off by a bit. (Anonymous) I think Microsoft named .Net so it wouldn’t show up in a Unix directory listing. (Oktal) Come to think of it, there are already a million monkeys on a million typewriters, and Usenet is nothing like Shakespeare. (Blair Houghton)"
console.log(fixRunts(str))
// Output: 640K ought to be enough for anybody. (Bill Gates, 1981) The best thing about a boolean is even if you are wrong, you are only off by a bit. (Anonymous) I think Microsoft named .Net so it wouldn’t show up in a Unix directory listing. (Oktal) Come to think of it, there are already a million monkeys on a million typewriters, and Usenet is nothing like Shakespeare. (Blair Houghton)