Saltar al contenido principal

Estructuras de Datos 🟢

Elegir la estructura correcta comunica que entiendes el problema. Esta guía cubre las estructuras más frecuentes en entrevistas junior.

Stack<T> — LIFO (último en entrar, primero en salir)

Un Stack (pila) funciona como una pila de platos: solo puedes agregar o quitar del tope.

var historial = new Stack<string>();

// Navegar páginas (Push agrega al tope)
historial.Push("inicio");
historial.Push("productos");
historial.Push("detalle/42");

// Volver atrás (Pop quita del tope)
string paginaActual = historial.Pop(); // "detalle/42"
string paginaAnterior = historial.Pop(); // "productos"

// Ver sin quitar
string siguiente = historial.Peek(); // "inicio" (sin modificar el stack)

Console.WriteLine($"Quedan: {historial.Count} páginas"); // 1

Casos de uso:

  • Historial de navegación (botón "Atrás")
  • Deshacer/rehacer en editores de texto (Ctrl+Z)
  • Evaluación de expresiones matemáticas (3 + (4 * 2))
  • Llamadas recursivas (el call stack de .NET es literalmente un Stack)

Queue<T> — FIFO (primero en entrar, primero en salir)

Una Queue (cola) funciona como una fila de caja: el primero que llega es el primero en ser atendido.

var colaImpresion = new Queue<string>();

// Enviar documentos a imprimir
colaImpresion.Enqueue("factura.pdf");
colaImpresion.Enqueue("contrato.docx");
colaImpresion.Enqueue("imagen.png");

// Imprimir en orden de llegada
string primero = colaImpresion.Dequeue(); // "factura.pdf"
string segundo = colaImpresion.Dequeue(); // "contrato.docx"

// Ver el siguiente sin quitarlo
string enEspera = colaImpresion.Peek(); // "imagen.png"

Casos de uso:

  • Cola de impresión (primer trabajo → primero en imprimirse)
  • Procesamiento de mensajes / eventos en orden de llegada
  • BFS (búsqueda en anchura) en grafos
  • Sistemas de tickets de soporte

Comparación Stack vs Queue

Stack<T>Queue<T>
OrdenLIFO — último primeroFIFO — primero primero
AgregarPush(item)Enqueue(item)
QuitarPop()Dequeue()
Ver sin quitarPeek()Peek()
Caso de uso típicoHistorial, deshacerColas de trabajo, mensajes
// Truco mnemotécnico:
// Stack → como una PILA de platos, agregas y sacas POR ARRIBA
// Queue → como una FILA de personas, entras por atrás, sales por adelante

LinkedList<T> — lista doblemente enlazada

Una LinkedList<T> conecta nodos entre sí. Cada nodo conoce el anterior y el siguiente.

var lista = new LinkedList<string>();

lista.AddLast("B");
lista.AddFirst("A"); // A ↔ B
lista.AddLast("C"); // A ↔ B ↔ C

// Insertar en medio: O(1) si ya tienes el nodo de referencia
var nodoB = lista.Find("B");
lista.AddAfter(nodoB, "B2"); // A ↔ B ↔ B2 ↔ C

// Eliminar: O(1) si ya tienes el nodo
lista.Remove(nodoB); // A ↔ B2 ↔ C

Cuándo elegir LinkedList<T> sobre List<T>:

OperaciónList<T>LinkedList<T>
Acceso por índice (list[3])O(1) ✅O(N) ❌
Insertar al principioO(N) ❌O(1) ✅
Insertar en medio (con referencia)O(N) ❌O(1) ✅
Recorrer todosO(N)O(N)

En la práctica, List<T> es la opción por defecto. LinkedList<T> brilla cuando haces muchas inserciones/eliminaciones al inicio o en el medio y tienes referencias directas a los nodos.


Cuándo usar cada estructura

¿Necesitas acceso por índice (lista[i])?
→ List<T>

¿Buscas frecuentemente por clave?
→ Dictionary<K, V>

¿El último en entrar debe salir primero (LIFO)?
→ Stack<T>

¿El primero en entrar debe salir primero (FIFO)?
→ Queue<T>

¿Muchas inserciones/eliminaciones en el medio?
→ LinkedList<T>

¿Solo necesitas iterar sin modificar?
→ IEnumerable<T> (la interfaz más genérica)

Resumen de complejidades

EstructuraAgregar al finalAgregar al inicioBuscar por valorAcceso por índice
List<T>O(1)*O(N)O(N)O(1)
Stack<T>O(1)* PushO(N)
Queue<T>O(1)* EnqueueO(N)
LinkedList<T>O(1)O(1)O(N)O(N)
Dictionary<K,V>O(1)*O(1)*
HashSet<T>O(1)*O(1)*

* Amortizado: puede redimensionarse internamente de vez en cuando.