Algoritmos y estructuras de datos en JavaScript (Node.js): desde lo básico hasta técnicas avanzadas
Comprender los algoritmos y las estructuras de datos es una habilidad fundamental para cualquier desarrollador que trabaje con JavaScript, especialmente en el entorno Node.js. Sin este conocimiento, es imposible crear aplicaciones eficientes, escalables y rápidas. En este artículo, analizaremos los conceptos clave que te ayudarán a escribir código optimizado y a superar con éxito las entrevistas técnicas.
¿Por qué son importantes los algoritmos y las estructuras de datos para Node.js?
Node.js, construido sobre el motor V8, permite ejecutar JavaScript en el servidor. Aquí, a diferencia del navegador, el rendimiento es crítico: el servidor procesa miles de solicitudes simultáneamente. Una elección incorrecta de la estructura de datos puede ralentizar el trabajo cientos de veces. Por ejemplo, buscar un elemento en un array de 10 000 registros puede llevar 0.1 ms, mientras que en una lista enlazada puede llevar 10 ms. La diferencia es evidente.
Las principales estructuras de datos que utilizarás:
- Arrays (Array) — una herramienta básica pero potente. Acceso rápido por índice (O(1)), pero inserción/eliminación lenta al principio (O(n)).
- Tablas hash (Object, Map) — ideales para almacenar pares "clave-valor". La complejidad media de las operaciones es O(1).
- Listas enlazadas (LinkedList) — eficientes para inserciones y eliminaciones frecuentes en medio de la lista.
- Pilas y colas (Stack, Queue) — indispensables para procesar flujos de datos (por ejemplo, tareas en el event loop).
- Árboles (Binary Tree, BST) — para datos jerárquicos y búsqueda rápida.
- Grafos (Graph) — para modelar relaciones (redes sociales, rutas).
Algoritmos básicos de ordenamiento y búsqueda en JavaScript
Veamos dos problemas clásicos: ordenar un array y la búsqueda binaria. En Node.js, estos algoritmos se implementan directamente, sin bibliotecas de terceros.
Ordenamiento rápido (Quick Sort)
Este es uno de los algoritmos más eficientes con una complejidad media de O(n log n). Funciona según el principio de "divide y vencerás".
function quickSort(arr) { if (arr.length <= 1) return arr;
const pivot = arr[arr.length - 1]; const left = []; const right = [];
for (let i = 0; i < arr.length - 1; i++) { if (arr[i] < pivot) { left.push(arr[i]); } else { right.push(arr[i]); } }
return [...quickSort(left), pivot, ...quickSort(right)];}
// Ejemplo de usoconst numbers = [34, 7, 23, 32, 5, 62];console.log(quickSort(numbers)); // [5, 7, 23, 32, 34, 62]Búsqueda binaria (Binary Search)
Algoritmo para arrays ordenados. Complejidad O(log n) — un orden de magnitud más rápido que la búsqueda lineal.
function binarySearch(arr, target) { let left = 0; let right = arr.length - 1;
while (left <= right) { const mid = Math.floor((left + right) / 2);
if (arr[mid] === target) return mid; if (arr[mid] < target) left = mid + 1; else right = mid - 1; }
return -1; // elemento no encontrado}
const sortedArray = [1, 3, 5, 7, 9, 11, 13];console.log(binarySearch(sortedArray, 7)); // 3Tablas hash: cuando el rendimiento importa
En Node.js, las tablas hash se implementan a través de los objetos incorporados Map y Object. Proporcionan acceso a los datos en O(1) en promedio. Sin embargo, es importante entender cómo evitar colisiones y pérdida de rendimiento.
Ejemplo: conteo de frecuencia de palabras usando Map
function countWords(text) { const wordMap = new Map(); const words = text.toLowerCase().split(/\\W+/);
for (const word of words) { if (word) { wordMap.set(word, (wordMap.get(word) || 0) + 1); } }
return wordMap;}
const text = "JavaScript y Node.js. JavaScript — es un lenguaje de programación";