edubun
Português

Filas

Tirar o primeiro de 1000 valores de um array de JavaScript com shift move os outros 999; um buffer circular faz o mesmo trabalho em um passo.

Primeiro a entrar, primeiro a sair

Uma fila é uma fila no balcão de uma loja. As pessoas entram pelo fim e são atendidas pela frente, então quem chegou primeiro sai primeiro. A regra é primeiro a entrar, primeiro a sair (FIFO). As duas operações são enqueue (enfileirar), que acrescenta um valor no fim, e dequeue (desenfileirar), que remove o valor da frente. Nas notas do 6.006 do MIT, uma fila é a interface de sequência limitada a insert last(x) e delete first().

As filas aparecem em todo lugar em que o trabalho precisa ser tratado na ordem de chegada: documentos esperando uma impressora, teclas apertadas esperando um programa, mensagens esperando um servidor. A busca em largura, do curso de algoritmos, guarda numa fila os quadrados que ainda precisa visitar, e é exatamente por isso que ela explora em anéis de mesma distância.

O jeito fácil e o seu custo escondido

Em JavaScript, a fila óbvia é um array: push para enfileirar no fim e shift para desenfileirar da frente. Funciona, e para filas curtas está bom. Mas veja o que o shift faz. O MDN diz que ele "desloca todos os valores 1 posição para a esquerda", e a especificação ECMAScript o escreve como um laço que copia o elemento k para a posição k − 1, para todo k. A frente de um array é a ponta cara, como a primeira unidade mostrou. Desenfileirar de uma fila de n valores custa 1 leitura mais n − 1 movimentos, então uma fila de 1000 valores custa 1000 passos por desenfileiramento. (Os motores podem usar atalhos internos, mas a especificação não promete nada.)

Se você enfileira 5 valores num array vazio e depois desenfileira os 5, os enfileiramentos custam 5 passos e os desenfileiramentos custam 5 + 4 + 3 + 2 + 1 = 15, 20 no total. A maior parte disso é mover valores que nem estão sendo removidos.

Não mova os valores, mova a frente

A solução é parar de mover os valores e, em vez disso, lembrar onde está a frente. Guarde um índice chamado head. O dequeue lê o valor em head e soma 1 a head; nada mais se move. O porém é que as células antes de head ficam desperdiçadas. Um buffer circular (ring buffer) as reaproveita: o array tem um número fixo de células, digamos 8, e as posições dão a volta, então a célula depois da 7 é a 0. Guarde head e size. O próximo enqueue vai para a célula (head + size) mod 8, e um dequeue pega a célula head e passa head para (head + 1) mod 8. As duas operações custam 1 passo. O preço é uma capacidade fixa: quando size chega a 8 a fila está cheia, a menos que você copie tudo para um anel maior, como faria um array dinâmico.

Carregando

Arraste para girar. Role ou faça pinça para dar zoom.

Uma fila de quatro valores. Com "Array com shift", todo desenfileiramento move o resto da fila. Mude o tipo para "Buffer circular" e os valores ficam onde estão enquanto head e o fim andam pelo anel.
Experimente no laboratório: mude para o buffer circular, enfileire quatro vezes para encher as 8 células e enfileire mais uma vez. O laboratório recusa, porque um anel fixo não tem nona célula. Depois desenfileire duas vezes e enfileire de novo: o valor novo vai para a célula 0, dando a volta.
Fila com n valoresEnfileirarDesenfileirar
Array com push e shift1 (amortizado)1 leitura + (n − 1) movimentos
Array com índice head1 (amortizado)1, mas as células da frente são desperdiçadas
Buffer circular de tamanho fixo1, ou cheio1

Qual usar? Para uma fila que nunca tem mais que algumas dezenas de valores, push e shift é curto e claro, e a movimentação quase não custa nada. Para uma fila por onde passam milhares de itens, como os quadrados de uma busca em largura grande, um índice head ou um buffer circular mantém cada desenfileiramento em um passo, e a diferença cresce com o comprimento da fila.

FIFOPrimeiro a entrar, primeiro a sair: os valores saem na ordem em que chegaram.
Enqueue / dequeueAcrescentar no fim / remover da frente.
shiftRemove o primeiro valor do array e move todos os outros uma célula para a esquerda.
Buffer circularUm array fixo usado em círculo: a próxima célula livre é (head + size) mod capacidade.
  1. Em que ordem uma fila devolve os valores?
    • Primeiro a entrar, primeiro a sair
    • Último a entrar, primeiro a sair
    • O maior primeiro
    • Ordem aleatória
  2. Enfileire A, B, C. Desenfileire uma vez. Enfileire D. Agora desenfileire até esvaziar. Ponha esses valores em ordem.
  3. Com push e shift, quantos passos leva um desenfileiramento numa fila de 4 valores (1 leitura mais movimentos)?
  4. Mesmo método, uma fila de 1000 valores: quantos passos para um desenfileiramento?
  5. Comece com um array vazio. Enfileire 5 valores com push e depois desenfileire os 5 com shift. Quantos passos no total?
  6. Um buffer circular tem 8 células (0 a 7), head = 6 e size = 3. Qual célula o próximo enfileiramento usa?
  7. Quantos passos leva um desenfileiramento num buffer circular, seja quantos forem os valores?
  8. Um anel fixo de 8 células tem 8 valores. O que acontece num enfileiramento?
    • Sobrescreve o valor da frente
    • A fila está cheia e o valor é recusado
    • Move todos os valores para a esquerda
    • Ordena os valores
  9. Qual busca do curso de algoritmos guarda os quadrados que esperam numa fila?
    • Busca binária
    • Busca em largura
    • Busca em profundidade
    • Busca linear
  10. Nos termos do MIT 6.006, uma fila usa quais duas operações de sequência?
    • insert last e delete last
    • insert last e delete first
    • insert first e delete first
    • get at e set at
Pontos-chave
  • Uma fila é primeiro a entrar, primeiro a sair: enfileira no fim, desenfileira da frente.
  • O shift move todos os valores restantes, então desenfileirar de n valores custa n passos.
  • Um índice head ou um buffer circular faz o desenfileiramento custar 1 passo.
  • Num anel de tamanho c, a próxima célula livre é (head + size) mod c.
Fontes deste 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).

Data de verificação: 2026-10-18