Tabla de contenido

Las estructuras de datos son una de esas materias que muchos desarrolladores evitan porque suena complicado, pero son fundamentales para escribir código eficiente. No necesitas ser un científico computacional para entenderlas: son formas de organizar datos según el problema que quieres resolver.

¿Por qué aprender estructuras de datos?

Imagina que tienes que gestionar 1 millón de registros. Dependiendo de qué estructura uses, una operación puede tardar microsegundos o varios minutos. La diferencia está en elegir la herramienta correcta.

Además, son preguntas frecuentes en entrevistas técnicas de trabajo. Pero más importante que eso: entenderlas te hace mejor programador porque te obliga a pensar en la eficiencia de tu código.

Array (Arreglo)

El array es la estructura más básica. Es una colección de elementos almacenados en posiciones contiguas de memoria, accesibles por su índice numérico.

const frutas = ["manzana", "pera", "naranja", "uva"];

// Acceso por índice (O(1) - instantáneo)
console.log(frutas[0]); // "manzana"
console.log(frutas[2]); // "naranja"

// Modificar
frutas[1] = "mango";

// Agregar al final (O(1) amortizado)
frutas.push("sandía");

// Eliminar del final (O(1))
frutas.pop();

// Agregar al inicio (O(n) - costoso, mueve todos los elementos)
frutas.unshift("fresa");

// Eliminar del inicio (O(n) - costoso)
frutas.shift();

// Buscar (O(n) - hay que revisar uno por uno)
const idx = frutas.indexOf("pera");

Fortalezas del array:

  • Acceso instantáneo por índice
  • Iteración eficiente
  • Poco overhead de memoria

Debilidades:

  • Insertar/eliminar en el medio o inicio es costoso (hay que mover elementos)
  • En algunos lenguajes tiene tamaño fijo

Lista Enlazada

Una lista enlazada es una serie de nodos donde cada nodo contiene un valor y una referencia (puntero) al siguiente nodo. A diferencia del array, los nodos no necesitan estar en posiciones contiguas de memoria.

// Nodo individual
class Nodo {
  constructor(valor) {
    this.valor = valor;
    this.siguiente = null;
  }
}

// Lista enlazada simple
class ListaEnlazada {
  constructor() {
    this.cabeza = null;
    this.tamano = 0;
  }
  
  // Agregar al inicio (O(1))
  prepend(valor) {
    const nuevo = new Nodo(valor);
    nuevo.siguiente = this.cabeza;
    this.cabeza = nuevo;
    this.tamano++;
  }
  
  // Agregar al final (O(n))
  append(valor) {
    const nuevo = new Nodo(valor);
    if (!this.cabeza) {
      this.cabeza = nuevo;
    } else {
      let actual = this.cabeza;
      while (actual.siguiente) {
        actual = actual.siguiente;
      }
      actual.siguiente = nuevo;
    }
    this.tamano++;
  }
  
  // Imprimir todos los valores
  imprimir() {
    let actual = this.cabeza;
    const valores = [];
    while (actual) {
      valores.push(actual.valor);
      actual = actual.siguiente;
    }
    console.log(valores.join(""));
  }
}

const lista = new ListaEnlazada();
lista.append("A");
lista.append("B");
lista.append("C");
lista.prepend("inicio");
lista.imprimir(); // "inicio → A → B → C"

Fortalezas:

  • Insertar/eliminar al inicio es O(1)
  • Tamaño dinámico (no hay que declarar el tamaño)

Debilidades:

  • Acceder a un elemento requiere recorrer la lista desde el inicio (O(n))
  • Más memoria por los punteros

Pila (Stack)

Una pila (stack) es una estructura LIFO: Last In, First Out. El último elemento en entrar es el primero en salir. Piensa en una pila de platos: solo puedes poner o quitar desde arriba.

class Pila {
  constructor() {
    this.items = [];
  }
  
  // Agregar al tope (O(1))
  push(elemento) {
    this.items.push(elemento);
  }
  
  // Sacar del tope (O(1))
  pop() {
    if (this.estaVacia()) return null;
    return this.items.pop();
  }
  
  // Ver el tope sin quitar (O(1))
  peek() {
    return this.items[this.items.length - 1];
  }
  
  estaVacia() {
    return this.items.length === 0;
  }
  
  tamano() {
    return this.items.length;
  }
}

const pila = new Pila();
pila.push("A");
pila.push("B");
pila.push("C");

console.log(pila.peek()); // "C" (tope)
console.log(pila.pop());  // "C" (sale primero el último en entrar)
console.log(pila.pop());  // "B"
console.log(pila.peek()); // "A"

Casos de uso reales:

  • El historial de Ctrl+Z en editores
  • La pila de llamadas (call stack) de JavaScript
  • Validación de paréntesis equilibrados (()[]{})
  • Navegación hacia atrás en un navegador

Cola (Queue)

Una cola (queue) es una estructura FIFO: First In, First Out. El primero en entrar es el primero en salir. Como una fila del banco: el primero que llegó es el primero que se atiende.

class Cola {
  constructor() {
    this.items = [];
  }
  
  // Agregar al final (enqueue)
  enqueue(elemento) {
    this.items.push(elemento);
  }
  
  // Sacar del inicio (dequeue)
  dequeue() {
    if (this.estaVacia()) return null;
    return this.items.shift();
  }
  
  // Ver el frente sin quitar
  frente() {
    return this.items[0];
  }
  
  estaVacia() {
    return this.items.length === 0;
  }
}

const cola = new Cola();
cola.enqueue("Usuario 1");
cola.enqueue("Usuario 2");
cola.enqueue("Usuario 3");

console.log(cola.dequeue()); // "Usuario 1" (primero en entrar)
console.log(cola.dequeue()); // "Usuario 2"
console.log(cola.frente());  // "Usuario 3"

Casos de uso reales:

  • Cola de impresión
  • Sistema de mensajes/notificaciones
  • Procesamiento de tareas en orden (job queues)
  • BFS (Breadth-First Search) en grafos

¿Cuándo usar cada estructura?

EstructuraUsar cuando…Ejemplo
ArrayNecesitas acceso rápido por índice o iterar en ordenLista de productos, datos de tabla
Lista enlazadaInsertas/eliminas frecuentemente al inicioHistorial de acciones
Pila (Stack)Necesitas LIFO: el último en entrar sale primeroDeshacer acciones, call stack
Cola (Queue)Necesitas FIFO: el primero en entrar sale primeroCola de espera, mensajes

Dominar estas cuatro estructuras básicas te dará las bases para entender estructuras más avanzadas como árboles, grafos y tablas hash. Todo se construye sobre estos fundamentos.