Algoritmos y estructuras de datos en JavaScript (Node.js): de principiante a profesional
Cada desarrollador de JavaScript, tarde o temprano, se enfrenta a la necesidad de comprender profundamente los algoritmos y las estructuras de datos. Independientemente de si escribes frontend en React o backend en Node.js, saber cómo organizar y procesar datos de manera eficiente es una habilidad clave. En este artículo, analizaremos las estructuras de datos básicas y los algoritmos populares con ejemplos prácticos en JavaScript para el entorno Node.js.
¿Por qué estudiar algoritmos y estructuras de datos?
Los algoritmos y las estructuras de datos son la base sobre la que se construye cualquier aplicación. La elección correcta de una estructura de datos puede acelerar la ejecución de un programa decenas de veces. Por ejemplo, buscar un elemento en un array de 10 000 elementos puede requerir hasta 10 000 operaciones, mientras que en una tabla hash solo una operación. Comprender estos principios ayuda a:
- Escribir código más eficiente
- Utilizar la memoria de manera eficaz
- Aprobar entrevistas técnicas
- Entender el funcionamiento interno de bibliotecas y frameworks populares
Estructuras de datos principales en JavaScript
Arrays
Los arrays son la estructura de datos más común en JavaScript. Almacenan elementos en orden secuencial y proporcionan acceso por índice en O(1). En Node.js, los arrays son especialmente útiles para trabajar con flujos de datos.
// Ejemplo de trabajo con arrays en Node.jsconst numbers = [5, 2, 9, 1, 5, 6];
// Añadir un elemento al finalnumbers.push(10); // [5, 2, 9, 1, 5, 6, 10]
// Eliminar el último elementoconst last = numbers.pop(); // 10
// Buscar un elementoconst index = numbers.findIndex(num => num === 9); // 2
// Filtrarconst filtered = numbers.filter(num => num > 5); // [9, 6]
console.log(`Resultado del filtrado: ${filtered}`);Pila (Stack)
La pila funciona bajo el principio LIFO (Last In, First Out). Es una estructura ideal para tareas que requieren acceso al último elemento añadido: historial de acciones (undo/redo), verificación de paréntesis, recorrido de grafos.
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; }}
// Ejemplo: verificar paréntesis correctosfunction 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("({[})")); // falseCola (Queue)
La cola funciona bajo el principio FIFO (First In, First Out). Es indispensable para procesar tareas en el orden en que llegan: planificadores de tareas, colas de mensajes, BFS (recorrido en anchura).
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; }}
// Ejemplo: simulación de cola de impresiónconst printQueue = new Queue();printQueue.enqueue("document1.pdf");printQueue.enqueue("document2.pdf");printQueue.enqueue("photo.jpg");
while (!printQueue.isEmp