Algorithms and Data Structures in JavaScript (Node.js): From Beginner to Pro
Every JavaScript developer sooner or later faces the need for a deep understanding of algorithms and data structures. Whether you write frontend in React or backend in Node.js, knowing how to efficiently organize and process data is a key skill. In this article, we will cover basic data structures and popular algorithms with practical examples in JavaScript for the Node.js environment.
Why Study Algorithms and Data Structures?
Algorithms and data structures are the foundation upon which any application is built. The right choice of data structure can speed up program execution by tens of times. For example, searching for an element in an array of 10,000 elements can take up to 10,000 operations, while in a hash table it takes just one operation. Understanding these principles helps:
- Write more performant code
- Use memory efficiently
- Pass technical interviews
- Understand the internal workings of popular libraries and frameworks
Basic Data Structures in JavaScript
Arrays
Arrays are the most common data structure in JavaScript. They store elements in sequential order and provide index-based access in O(1). In Node.js, arrays are especially useful for working with data streams.
// Example of working with arrays in Node.jsconst numbers = [5, 2, 9, 1, 5, 6];
// Adding an element to the endnumbers.push(10); // [5, 2, 9, 1, 5, 6, 10]
// Removing the last elementconst last = numbers.pop(); // 10
// Searching for an elementconst index = numbers.findIndex(num => num === 9); // 2
// Filteringconst filtered = numbers.filter(num => num > 5); // [9, 6]
console.log(`Filtering result: ${filtered}`);Stack
A stack operates on the LIFO (Last In, First Out) principle. It is an ideal structure for tasks where access to the last added element is needed: action history (undo/redo), bracket checking, graph traversal.
class Stack { constructor() { this.items = []; }
push(element) { this.items.push(element); }
pop() { if (this.isEmpty()) return null; return this.items.pop(); }
peek() { if (this.isEmpty()) return null; return this.items[this.items.length - 1]; }
isEmpty() { return this.items.length === 0; }
size() { return this.items.length; }}
// Example: checking bracket correctnessfunction isValidParentheses(str) { const stack = new Stack(); const pairs = { '(': ')', '{': '}', '[': ']' };
for (let char of str) { if (pairs[char]) { stack.push(char); } else { const last = stack.pop(); if (pairs[last] !== char) return false; } }
return stack.isEmpty();}
console.log(isValidParentheses("({[]})")); // trueconsole.log(isValidParentheses("({[})")); // falseQueue
A queue operates on the FIFO (First In, First Out) principle. It is indispensable for processing tasks in the order they arrive: task schedulers, message queues, BFS (breadth-first search).
class Queue { constructor() { this.items = {}; this.front = 0; this.rear = 0; }
enqueue(element) { this.items[this.rear] = element; this.rear++; }
dequeue() { if (this.isEmpty()) return null; const item = this.items[this.front]; delete this.items[this.front]; this.front++; return item; }
isEmpty() { return this.front === this.rear; }
size() { return this.rear - this.front; }}
// Example: simulating a print queueconst printQueue = new Queue();printQueue.enqueue("document1.pdf");printQueue.enqueue("document2.pdf");printQueue.enqueue("photo.jpg");
while (!printQueue.isEmp