edubun
Español

Arreglos

Leer el valor número un millón de un arreglo lleva un paso, pero poner un valor nuevo al principio del mismo arreglo mueve un millón de valores.

Qué es una estructura de datos

Un programa que guarda una lista de nombres, una cola de trabajos de impresión o una tabla de precios tiene que almacenar esos datos en algún lugar, y tiene que responder preguntas sobre ellos: ¿cuál es el tercer elemento?, ¿está este nombre en la lista?, ¿qué trabajo sigue? Una estructura de datos es una forma de guardar datos junto con los métodos que responden esas preguntas. El curso 6.006 del MIT separa aquí dos ideas. La interfaz dice qué operaciones puedes pedir, como "obtener el elemento de la posición i" o "agregar un elemento al final". La estructura de datos es cómo se llevan a cabo realmente esas operaciones en la memoria. Detrás de una misma interfaz puede haber varias estructuras de datos, y su velocidad puede ser muy distinta.

Este curso cuenta pasos, como el curso de algoritmos, para poder comparar dos estructuras sin cronómetro. En esta unidad, un paso es leer o escribir una celda de memoria. El laboratorio de abajo los cuenta por ti.

Un bloque de celdas, una junto a otra

Un arreglo guarda sus valores en un solo bloque continuo de memoria, cada valor en una celda del mismo tamaño, numeradas desde 0. Esa disposición es lo que hace que los arreglos se lean rápido. Si el bloque empieza en la dirección s y cada celda ocupa c bytes, entonces a[i] está en la dirección s + i × c. La computadora lo calcula con una multiplicación y una suma y salta directamente ahí, sea i igual a 3 o a 3 000 000. Las notas del MIT dan "get at(i)" y "set at(i, x)" de un arreglo como Θ(1), lo que significa que el costo no crece con la longitud.

La misma disposición hace que los cambios en el medio sean lentos. Supón que el arreglo contiene 7, 3, 9, 4, 6 y quieres poner 1 al principio. No hay hueco delante del 7, así que primero cada valor tiene que moverse una celda a la derecha, empezando por el último para no sobrescribir nada. Son 5 movimientos y 1 escritura: 6 pasos. Quitar el primer valor es lo contrario: leerlo y luego mover los otros 4 valores una celda a la izquierda. Insertar en la posición i de un arreglo de n valores cuesta n − i movimientos más una escritura, así que el principio es el peor lugar y el final, el mejor.

Cargando

Arrastra para girar. Desplaza o pellizca para acercar.

Un arreglo de cinco valores en un bloque de cinco celdas. Mueve el control deslizante para elegir i y luego lee, inserta o elimina. Agregar un valor al bloque lleno copia todo en un bloque del doble de tamaño.

Cuando el bloque se llena

Un bloque de memoria tiene un tamaño fijo, así que ¿qué pasa cuando agregas un valor y todas las celdas están ocupadas? El arreglo tiene que pedir un bloque nuevo y más grande y copiar ahí todos los valores antes de poder escribir el nuevo. En el laboratorio, agregar un valor al bloque lleno de 5 cuesta 5 copias y 1 escritura. Si el arreglo creciera de una en una celda, cada push copiaría todo, y n push costarían unas n²/2 copias.

La solución que describen las notas del MIT es crecer mucho de una vez, por ejemplo duplicando el tamaño. Empezando con capacidad 1, las copias ocurren cuando el arreglo tiene 1, 2, 4, 8 y 16 valores, así que 17 push cuestan en total 1 + 2 + 4 + 8 + 16 = 31 copias, menos de 2 por push. Un push suelto puede seguir siendo lento, pero cualquier serie larga de push sale en promedio a un costo constante por push. Esto se llama tiempo Θ(1) amortizado. Un arreglo de JavaScript se comporta así visto desde fuera: MDN describe los arreglos como redimensionables, y push y pop trabajan en el final, que es el extremo barato.

Operación sobre n valoresPasos en el laboratorioCrece como
Leer o escribir a[i]1Θ(1)
Insertar al principion movimientos + 1 escrituraΘ(n)
Quitar el primero1 lectura + (n − 1) movimientosΘ(n)
Push al final (con espacio libre)1Θ(1)
Push al final (bloque lleno)n copias + 1 escrituraΘ(n) una vez, Θ(1) amortizado
const a = [7, 3, 9, 4, 6];
console.log(a[3]);      // 4, un paso
a.push(8);              // barato: el final
a.unshift(1);           // cada valor se mueve una celda a la derecha
console.log(a.join(" ")); // 1 7 3 9 4 6 8
ContextoLos arreglos son más antiguos que la mayoría de los lenguajes de programación. Las primeras máquinas guardaban una tabla como palabras numeradas en la memoria, y los programadores calculaban a mano la dirección de la entrada i, exactamente como hace la fórmula de arriba. Fortran, lanzado por IBM en 1957, hizo de los arreglos parte del lenguaje para que se pudiera escribir A(I) y dejar que el compilador hiciera la aritmética de direcciones. Fortran contaba desde 1. C y JavaScript cuentan desde 0, lo que encaja con la fórmula: a[0] está en la propia dirección inicial.
InterfazLa lista de operaciones que puedes pedir, como get at(i) o insert last(x).
Estructura de datosCómo se llevan a cabo esas operaciones en la memoria.
ArregloValores en un bloque de celdas iguales; a[i] está en inicio + i × tamaño de celda.
Arreglo dinámicoUn arreglo que crece copiándose en un bloque más grande, normalmente del doble de tamaño.
Costo amortizadoEl costo promedio por operación en una serie larga, aunque algunas operaciones sueltas sean lentas.
  1. Con el conteo de pasos de esta unidad, ¿cuántos pasos lleva leer a[700000] de un arreglo de 1 000 000 de valores?
    • 1
    • 20
    • 700,000
    • 1,000,000
  2. Un arreglo contiene 7, 3, 9, 4, 6 y tiene espacio de sobra. ¿Cuántos pasos lleva insertar un valor al principio (movimientos más la escritura)?
  3. El mismo arreglo de 5 valores: ¿cuántos pasos lleva quitar el primer valor (1 lectura más los movimientos)?
  4. Insertar en la posición 2 de un arreglo de 5 valores (posiciones de 0 a 4) con espacio libre: ¿cuántos pasos?
  5. Un arreglo que se duplica contiene 5 valores y su capacidad es 5. Agregas un valor más con push. ¿Cuántos pasos lleva ese push?
  6. Después de ese push, ¿cuál es la capacidad?
  7. Empezando con capacidad 1 y duplicando, ¿cuántas copias hacen en total 17 push?
  8. ¿Por qué se dice que push en un arreglo que se duplica es Θ(1) amortizado?
    • Cada push lleva exactamente un paso
    • Las copias son poco frecuentes, así que el total de n push se mantiene por debajo de una constante por n
    • La computadora copia en segundo plano gratis
    • JavaScript nunca copia arreglos
  9. En los términos del 6.006 del MIT, "insert last(x) y delete last()" es
    • una estructura de datos
    • una interfaz
    • una dirección de memoria
    • un método de ordenamiento
  10. Un arreglo tiene longitud n y cuenta desde 0. ¿Cuál es el índice de su último valor?
    • n
    • n − 1
    • n + 1
    • 1
Ideas clave
  • Una interfaz enumera operaciones; una estructura de datos es cómo se hacen.
  • Un arreglo guarda los valores en un solo bloque, así que a[i] es un paso.
  • Insertar o quitar cerca del principio mueve unos n valores.
  • Un arreglo que se duplica hace que push sea Θ(1) amortizado: 17 push desde capacidad 1 copian 31 valores.
Fuentes de este curso (11)
  • MIT OpenCourseWare 6.006 Introduction to Algorithms, Spring 2020 (Demaine, Ku, Solomon)
  • lecture notes 2 Data Structures (interface vs data structure, Sequence and Set interfaces, stack = insert_last/delete_last, queue = insert_last/delete_first, array, linked list, dynamic array, amortized Θ(1) append)
  • 4 Hashing (chaining, pigeonhole collisions, chain length n/m)
  • 6 Binary Trees Part 1 (height, traversal order, O(h) operations) and 7 Binary Trees Part 2: AVL (Adelson-Velsky and Landis, 1962) at ocw.mit.edu/courses/6-006-introduction-to-algorithms-spring-2020/pages/lecture-notes
  • MDN Web Docs, Array.prototype.shift (shifts all values left by 1)
  • Array.prototype.unshift, Map (insertion order, Map vs Object, spec requires sublinear average access) and Set (developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects)
  • ECMAScript 2025 Language Specification (tc39.es/ecma262)
  • 24.1 Map Objects and 24.2 Set Objects ("must be implemented using either hash tables or other mechanisms that, on average, provide access times that are sublinear on the number of elements")
  • Array.prototype.shift steps (Repeat, while k < len: move element k to k - 1)
  • D. E. Knuth, The Art of Computer Programming vol. 3 (2nd ed. 1998) section 6.4 History (H. P. Luhn, IBM internal memorandum January 1953, hashing with chaining; digit pairs added mod 10, 31415926 -> 4548) via gwern.net copy, and IEEE Spectrum, "Hans Peter Luhn and the Birth of the Hashing Algorithm" (2018)
  • "A brief history of the stack", SIGCIS (sigcis.org/files/A brief history.pdf: Bauer and Samelson applied for the patent in 1957, US 3,047,228 granted July 31, 1962; IPL list processing by Newell, Simon and Shaw at RAND 1956) and Wikipedia, Information Processing Language (Newell, Shaw, Simon, RAND and Carnegie Institute of Technology, about 1956).

Fecha de consulta: 2026-10-18