edubun
Italiano

Code

Togliere il primo di 1000 valori da un array di JavaScript con shift sposta gli altri 999; un buffer circolare fa lo stesso lavoro in un passo.

Il primo entrato è il primo a uscire

Una coda è la fila al bancone di un negozio. Le persone si mettono in fondo e vengono servite dalla testa, così chi è arrivato per primo esce per primo. La regola è first in, first out (FIFO): il primo entrato è il primo a uscire. Le due operazioni sono accodare (enqueue), che aggiunge un valore in fondo, ed estrarre (dequeue), che toglie il valore in testa. Negli appunti del corso 6.006 del MIT una coda è l'interfaccia di sequenza limitata a insert last(x) e delete first().

Le code sono ovunque il lavoro vada gestito in ordine di arrivo: documenti in attesa di una stampante, tasti premuti in attesa di un programma, messaggi in attesa di un server. La visita in ampiezza, dal corso di algoritmi, tiene in una coda le caselle che deve ancora visitare, ed è proprio per questo che esplora ad anelli di uguale distanza.

Il modo facile e il suo costo nascosto

In JavaScript la coda più ovvia è un array: push per accodare in fondo e shift per estrarre dalla testa. Funziona, e per code corte va bene. Ma guarda che cosa fa shift. MDN dice che «sposta tutti i valori a sinistra di 1», e la specifica ECMAScript lo scrive come un ciclo che copia l'elemento k nella posizione k − 1 per ogni k. La testa di un array è l'estremità costosa, come ha mostrato la prima unità. Estrarre da una coda di n valori costa 1 lettura più n − 1 spostamenti, quindi una coda di 1000 valori costa 1000 passi a ogni estrazione. (I motori possono usare scorciatoie al loro interno, ma la specifica non promette niente.)

Se accodi 5 valori in un array vuoto e poi li estrai tutti e 5, gli accodamenti costano 5 passi e le estrazioni 5 + 4 + 3 + 2 + 1 = 15, per 20 in tutto. Gran parte di questo lavoro è spostare valori che non vengono nemmeno tolti.

Non spostare i valori, sposta la testa

La soluzione è smettere di spostare i valori e ricordare invece dov'è la testa. Tieni un indice chiamato head. L'estrazione legge il valore in head e aggiunge 1 a head; nient'altro si sposta. Il problema è che le celle prima di head vanno sprecate. Un buffer circolare (ring buffer) le riusa: l'array ha un numero fisso di celle, per esempio 8, e le posizioni ricominciano dall'inizio, così la cella dopo la 7 è la 0. Memorizza head e size. Il prossimo accodamento va nella cella (head + size) mod 8, e un'estrazione prende la cella head e porta head a (head + 1) mod 8. Entrambe le operazioni costano 1 passo. Il prezzo è una capacità fissa: quando size arriva a 8 la coda è piena, a meno di copiare tutto in un anello più grande come farebbe un array dinamico.

Caricamento

Trascina per ruotare. Scorri o avvicina le dita per lo zoom.

Una coda di quattro valori. Con «Array con shift» ogni estrazione sposta il resto della fila. Cambia il tipo in «Buffer circolare» e i valori restano dove sono, mentre head e tail girano intorno all'anello.
Prova nel laboratorio: passa al buffer circolare, accoda quattro volte per riempire tutte le 8 celle e accoda ancora una volta. Il laboratorio rifiuta, perché un anello fisso non ha una nona cella. Poi estrai due volte e accoda di nuovo: il nuovo valore va nella cella 0, ricominciando il giro.
Coda di n valoriAccodareEstrazione
Array con push e shift1 (ammortizzato)1 lettura + (n − 1) spostamenti
Array con indice di testa1 (ammortizzato)1, ma le celle in testa vanno sprecate
Buffer circolare di dimensione fissa1, oppure pieno1

Quale conviene usare? Per una coda che non contiene mai più di qualche decina di valori, push e shift sono brevi e chiari, e gli spostamenti non costano quasi nulla. Per una coda attraverso cui passano migliaia di elementi, come le caselle di una grande visita in ampiezza, un indice di testa o un buffer circolare mantiene ogni estrazione a un passo, e la differenza cresce con la lunghezza della fila.

FIFOFirst in, first out: il primo entrato è il primo a uscire, quindi i valori escono nell'ordine in cui sono arrivati.
Accodamento / estrazioneAggiungi in fondo / togli dalla testa.
shiftToglie il primo valore dell'array e sposta tutti gli altri di una cella a sinistra.
Buffer circolareUn array fisso usato in cerchio: la prossima cella libera è (head + size) mod capacità.
  1. In quale ordine una coda restituisce i valori?
    • Il primo entrato è il primo a uscire
    • L'ultimo entrato è il primo a uscire
    • Prima il più grande
    • In ordine casuale
  2. Accoda A, B, C. Estrai una volta. Accoda D. Ora estrai finché la coda è vuota. Metti quei valori in ordine.
  3. Con push e shift, quanti passi richiede un'estrazione da una coda di 4 valori (1 lettura più gli spostamenti)?
  4. Stesso metodo, una coda di 1000 valori: quanti passi per un'estrazione?
  5. Parti da un array vuoto. Accoda 5 valori con push, poi estraili tutti e 5 con shift. Quanti passi in totale?
  6. Un buffer circolare ha 8 celle (da 0 a 7), head = 6 e size = 3. Quale cella usa il prossimo accodamento?
  7. Quanti passi richiede un'estrazione da un buffer circolare, qualunque sia il numero di valori che contiene?
  8. Un anello fisso di 8 celle contiene 8 valori. Che cosa succede all'accodamento?
    • Sovrascrive il valore in testa
    • La coda è piena e il valore viene rifiutato
    • Sposta ogni valore a sinistra
    • Ordina i valori
  9. Quale ricerca del corso di algoritmi tiene le caselle in attesa in una coda?
    • Ricerca binaria
    • Visita in ampiezza
    • Visita in profondità
    • Ricerca lineare
  10. Nei termini di MIT 6.006, quali due operazioni di sequenza usa una coda?
    • insert last e delete last
    • insert last e delete first
    • insert first e delete first
    • get at e set at
Punti chiave
  • Una coda è first in, first out: si accoda in fondo e si estrae dalla testa.
  • shift sposta ogni valore rimasto, quindi estrarre da n valori costa n passi.
  • Un indice di testa o un buffer circolare rende l'estrazione di 1 passo.
  • In un anello di dimensione c, la prossima cella libera è (head + size) mod c.
Fonti di questo corso (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).

Consultato il: 2026-10-18