Fila
1. O que são filas
Section titled “1. O que são filas”Seguindo com o conceito de tipos abstratos de dados, vamos verificar o que são filas e como elas podem ser utilizadas.
“Calma lá Murilão, eu sei o que são filas na vida real! Aqui é a mesma coisa?”
Boa analogia! As filas aqui incorporam o mesmo comportamento das filas da vida real. Na verdade, esse é o nosso objetivo quando estamos implementando esse tipo de dado. Nós utilizamos o TAD de Fila, quando desejamos implementar o comportamento do tipo FIFO.
O FIFO significa First In - First Out, onde o primeiro elemento que for adicionado na fila será o primeiro elemento que será removido dela. Esse é o comportamento essencial da fila, qualquer implementação com essa estrutura, tem por objetivo trazer esse comportamento para o sistema.
“Mas Murilo, onde isso é útil? Eu consigo ver isso na vida real, mas em código por que? Um vetor não faz isso e bora?”
Boa pergunta! Vamos pensar no porque utilizamos essas estruturas. Lembrem que a utilização dos TAD, traz um conjunto de interfaces que serão implementadas pelo nosso elemento, para que possamos colocar energia no desenvolvimento da nossa solução. Na vida real, é possível ver filas em diversos locais, como em caixas, as músicas em um player de música ou ainda os episódios que serão vistos em uma plataforma de streaming.
Vamos ver os contratos que essa interface traz para nós!
2. Propriedades e Contratos das Filas
Section titled “2. Propriedades e Contratos das Filas”Quando estamos trabalhando com Filas, temos algumas propriedades que devemos garantir que esses TAD implementam:
- Invariante FIFO: O primeiro elemento adicionado em uma fila deve ser o primeiro elemento removido dela.
- Comportamento consistente independentemente da implementação: Não faz diferença se a fila foi implementada utilizando um vetor ou alocação dinâmica, ela deve ter os mesmos comportamentos.
- Tratamento de underflow (dequeue em fila vazia): deve ser realizado algum tipo de implementação que sinalize que uma fila vazia tentou ter algum elemento removido dela.
Alguns dos contratos esperados que a TAD implemente:
TAD Fila OPERACOES: - enqueue(elemento) - dequeue() -> elemento - peek() -> elemento - isEmpty() -> booleano - size() -> inteiroOnde temos:
- enqueue(elemento): inserir ao final.
- dequeue() -> elemento: remover e retornar o elemento no início.
- peek() -> elemento: consultar o elemento no início sem remover.
- isEmpty() -> booleano: verificar se está vazia.
- size() -> inteiro: tamanho atual, a quantidade de elementos na fila.
Comparando a implementação de fila com um vetor e com alocação dinâmica, podemos destacar:
-
Usando Vetor (Array-Based Queue):
- Estrutura: array fixo ou redimensionável + ponteiros front e rear
- Vantagens e desvantagens (acesso O(1), deslocamentos, realocação)
-
Usando Lista Encadeada:
- Estrutura: nós com referência ao próximo + ponteiros de cabeça e cauda
- Vantagens e desvantagens (inserções/removals O(1), maior uso de memória)
3. Estudando um problema para implementar com listas
Section titled “3. Estudando um problema para implementar com listas”Ok, vamos então estudar um problema e ver como poderíamos resolver ele utilizando uma lista.
Você foi contratado para desenvolver o módulo “Lista de Ingredientes” de um sistema de pedidos online de um restaurante que oferece pratos 100% customizáveis. Cada cliente monta seu prato escolhendo ingredientes da “base” (por exemplo, arroz, macarrão, salada) e depois inserindo adicionais (como queijos, molhos, verduras, proteínas) no fim. O sistema precisa manter, para cada pedido, uma lista ordenada de ingredientes que:
-
Permita ao cliente inserir um ingrediente no final.
-
Permita ao cliente remover o primeiro ingrediente que foi adicionado.
-
Ofereça a funcionalidade de buscar por nome de ingrediente, retornando sua posição atual (ou indicando “não encontrado”).
-
Informe o tamanho da lista (quantos ingredientes já foram adicionados).
-
Verifique se a lista está vazia (por exemplo, antes de confirmar o pedido sem extras).
3.1 Tarefas para solucionar o problema
Section titled “3.1 Tarefas para solucionar o problema”Pessoal aqui vou construir com vocês uam solução para este problema. Existem outras soluções que também podem ser desenvolvidas. Vamos analisar essa em conjunto.
Descreva o TAD ListaIngredientes, listando seus atributos e operações com assinaturas semelhantes a:
TAD ListaIngredientes ATRIBUTOS: – dados: vetor ou encadeamento de Ingrediente – n: inteiro // tamanho atual da lista
OPERACOES: – inserir(posicao: inteiro, ing: Ingrediente) – inserirNoFim(ing: Ingrediente) – remover() – buscarPorNome(nome: texto) -> inteiro – tamanho() -> inteiro – estaVazia() -> booleanoModele o tipo Ingrediente com, pelo menos, os campos nome (texto) e calorias (inteiro).
TAD Ingrediente ATRIBUTOS: - nome : texto - calorias: inteiroVamos pensar agora no pseudo-código para realizar essas implementações.
# Definição dos tipos
TAD Ingrediente ATRIBUTOS: nome: texto calorias: inteiro
MÉTODOS: criar(nome: texto, calorias: inteiro) -> Ingrediente nova.nome ← nome nova.calorias ← calorias RETORNAR nova
TAD ListaIngredientes CONSTANTES: MAX ← 100 # capacidade máxima do vetor
ATRIBUTOS: dados: vetor[0..MAX-1] de Ingrediente n: inteiro # número atual de elementos
MÉTODOS:
criar() -> ListaIngredientes lista.dados ← vetor vazio de tamanho MAX lista.n ← 0 RETORNAR lista
inserir(posicao: inteiro, ing: Ingrediente) # validações SE lista.n = MAX ESCREVER "Erro: lista cheia" RETORNAR SE posicao < 0 OU posicao > lista.n ESCREVER "Erro: posição inválida" RETORNAR # desloca para a direita PARA i ← lista.n ATÉ posicao+1 PASSO -1 lista.dados[i] ← lista.dados[i-1] lista.dados[posicao] ← ing lista.n ← lista.n + 1
inserirNoFim(ing: Ingrediente) inserir(lista.n, ing)
remover() -> Ingrediente SE lista.n = 0 ESCREVER "Erro: lista vazia" RETORNAR nulo ing ← lista.dados[0] PARA i ← 0 ATÉ lista.n-2 lista.dados[i] ← lista.dados[i+1] lista.n ← lista.n - 1 RETORNAR ing
buscarPorNome(nome: texto) -> inteiro PARA i ← 0 ATÉ lista.n-1 SE lista.dados[i].nome = nome RETORNAR i RETORNAR -1 # não encontrado
tamanho() -> inteiro RETORNAR lista.n
estaVazia() -> booleano RETORNAR (lista.n = 0)
# Exemplo de uso (pseudocódigo)
função principal() lista ← criar()
# cria ingredientes queijo ← criar("Queijo", 200) bacon ← criar("Bacon", 300) alface ← criar("Alface", 10)
# operações inserirNoFim(queijo) # [Queijo] inserirNoFim(bacon) # [Queijo, Bacon] inserirNoFim(alface) # [Queijo, Alface, Bacon] remover() # remove “Queijo”: [Alface, Bacon]
posicaoBacon ← buscarPorNome("Queijo") # retorna -1 (não existe) tamLista ← tamanho() # retorna 2 vazia ← estaVazia() # retorna FALSO
ESCREVER "Posição do Queijo:", posicaoBacon ESCREVER "Tamanho da lista:", tamLista ESCREVER "Lista vazia?", vaziaBeleza! Vamos verificar essa proposta de solução e vamos ver como ela está realizando está implementação.
- Vamos analisar primeiro o programa principal. Vale perceber que a lista é criada antes de qualquer operação ser realizada com ela. Aqui são iniciados o vetor para armazenar os dados e o tamanho da lista é iniciado com zero.
- Os elementos do tipo
Ingredientesão criados. - Cada vez que a função
inserirNoFim()é chamada, ela faz uma chamada para a funçãoinserir(), mandando o tamanho atual da lista, assim o elemento é inserido no final dela. Na função, primeiro é verificado se a lista não está cheia. Depois, é verificada se a posição enviada não é invalida. Agora, um laço de repetição que vai do último elemento para a posição informada mais um, vai deslocando todos os elementos dentro da lista para a direita, pegando o elemento anterior ao atual pelo índiceie colocando ele na posiçãoi. Por fim, o elemento é inserido na lista e seu tamanho atual é atualizado. - Quando a função
remover()é invocada, o primeiro elemento que foi inserido será removido. Se a lista não estiver vazia, os itens da lista são deslocados para esquerda e o item removido é retornado.
Legal! Agora vamos ver um exemplo desse cara implementado com alguma linguagem de programação.
3.2 Implementação em C
Section titled “3.2 Implementação em C”Vamos verificar essa implementação:
#include <stdio.h>#include <string.h>#include <stdbool.h>
#define MAX 100 // capacidade máxima da lista
// Tipo Ingredientetypedef struct { char nome[50]; int calorias;} Ingrediente;
// Tipo ListaIngredientestypedef struct { Ingrediente dados[MAX]; int n; // número atual de elementos} ListaIngredientes;
// Cria uma lista vaziavoid criarLista(ListaIngredientes *lista) { lista->n = 0;}
// Verifica se a lista está vaziabool estaVazia(ListaIngredientes *lista) { return (lista->n == 0);}
// Retorna o tamanho da listaint tamanho(ListaIngredientes *lista) { return lista->n;}
// Insere ingrediente em posição específicabool inserir(ListaIngredientes *lista, int pos, Ingrediente ing) { if (lista->n >= MAX) { printf("Erro: lista cheia\n"); return false; } if (pos < 0 || pos > lista->n) { printf("Erro: posição inválida\n"); return false; } // desloca elementos para a direita for (int i = lista->n; i > pos; --i) { lista->dados[i] = lista->dados[i - 1]; } lista->dados[pos] = ing; lista->n++; return true;}
// Insere ingrediente ao fim da listabool inserirNoFim(ListaIngredientes *lista, Ingrediente ing) { return inserir(lista, lista->n, ing);}
// Remove ingrediente de posição específicabool removerPorPosicao(ListaIngredientes *lista, int pos) { if (estaVazia(lista)) { printf("Erro: lista vazia\n"); return false; } if (pos < 0 || pos >= lista->n) { printf("Erro: posição inválida\n"); return false; } // desloca elementos para a esquerda for (int i = pos; i < lista->n - 1; ++i) { lista->dados[i] = lista->dados[i + 1]; } lista->n--; return true;}
// Remove o primeiro elemento (comportamento de fila) e retorna cópiabool removerFila(ListaIngredientes *lista, Ingrediente *retirado) { if (estaVazia(lista)) { printf("Erro: lista vazia\n"); return false; } *retirado = lista->dados[0]; // desloca restante para a esquerda for (int i = 0; i < lista->n - 1; ++i) { lista->dados[i] = lista->dados[i + 1]; } lista->n--; return true;}
// Busca ingrediente por nome, retorna índice ou -1int buscarPorNome(ListaIngredientes *lista, const char *nome) { for (int i = 0; i < lista->n; ++i) { if (strcmp(lista->dados[i].nome, nome) == 0) { return i; } } return -1;}
// Imprime a lista (para debug)void imprimirLista(ListaIngredientes *lista) { printf("Lista de ingredientes (%d itens):\n", lista->n); for (int i = 0; i < lista->n; ++i) { printf(" [%d] %s (%d cal)\n", i, lista->dados[i].nome, lista->dados[i].calorias); }}
int main() { ListaIngredientes lista; criarLista(&lista);
Ingrediente queijo = { "Queijo", 200 }; Ingrediente bacon = { "Bacon", 300 }; Ingrediente alface = { "Alface", 10 };
// Operações de fila inserirNoFim(&lista, queijo); inserirNoFim(&lista, bacon); inserirNoFim(&lista, alface); imprimirLista(&lista);
// Remove o primeiro (estilo queue) Ingrediente primeiro; if (removerFila(&lista, &primeiro)) { printf("\nRemovido (fila): %s (%d cal)\n", primeiro.nome, primeiro.calorias); } imprimirLista(&lista);
// Remove genérico por posição removerPorPosicao(&lista, 1); // remove "Alface" printf("\nDepois de remover posição 1:\n"); imprimirLista(&lista);
// Buscas e status int posBacon = buscarPorNome(&lista, "Bacon"); printf("\nPosição do Bacon: %d\n", posBacon); printf("Tamanho da lista: %d\n", tamanho(&lista)); printf("Lista vazia? %s\n", estaVazia(&lista) ? "SIM" : "NÃO");
return 0;}Analisando a solução:
- A biblioteca
stdboolé utilizada para que as macrostrueefalsepossam ser utilizadas. - São definidas as duas estruturas de dados que serão utilizadas, uma para Ingredientes e outra para a Lista que vai se comportar como fila.
- A função
criarListarecebe por referencia o endereço da variável que irá armazenar a lista. Ele atualiza a quantidade de elementos para zero. - A função
buscarPorNome()utiliza a funçãostrcmppara verificar o elemento Ingrediente com os que estão no vetor.
4. Exercícios
Section titled “4. Exercícios”4.1 Supermercado
Section titled “4.1 Supermercado”Em um banco, clientes chegam e enfileiram-se para ser atendidos pelo caixa. Modele o TAD FilaClientes onde cada elemento armazena nome_cliente e tipo_conta. Defina operações:
- enqueue(cliente)
- dequeue() -> cliente
- peek() -> cliente
- isEmpty() -> booleano
- size() -> inteiro
Escolha uma linguagem de programação e faça as implementações. Simule: chega “Alice”, “Bruno”, “Carla”; atenda dois clientes; mostre quem está no início.
4.2 Fila de Impressão de Documentos
Section titled “4.2 Fila de Impressão de Documentos”Um escritório possui uma impressora compartilhada; documentos são enviados e aguardam na fila para serem impressos. Crie o TAD FilaImpressao em que cada job contém id_documento e num_paginas. Implemente métodos para:
- enqueue(job)
- dequeue() -> job
- isEmpty()
- totalJobs() -> inteiro
- Função que, após cada impressão, remove o job e exibe “Imprimindo doc X de Y páginas”.
Demonstre inserindo três jobs e processando todos até a fila zerar.
4.3 Buffer de Rede (Pacotes)
Section titled “4.3 Buffer de Rede (Pacotes)”Um roteador armazena pacotes de dados recebidos em uma fila antes de encaminhá-los. Modele FilaPacotes com campos origem, destino e tamanho_bytes. Adicione operação drop() que, ao detectar size > capacidade, simplesmente descarta (dequeue) o primeiro pacote sem retornar. Escreva pseudocódigo para enqueue, dequeue, drop e isEmpty. Simule a chegada de 5 pacotes, com overflow no terceiro, aplicando drop().
4.4 Fila de Pedidos em Restaurante
Section titled “4.4 Fila de Pedidos em Restaurante”Em um fast-food, os pedidos dos clientes entram em fila na cozinha. Defina Pedido com num_pedido, itens (lista de strings) e tempo_estimado. Modele FilaPedidos com enqueue, dequeue, peek e size.
Código que:
- Insere pedidos
- Quando o cozinheiro finaliza, faz dequeue() e registra “Pedido X pronto em T minutos”.
Demonstre três inserções e duas remoções.
4.5 Check-in em Aeroporto
Section titled “4.5 Check-in em Aeroporto”Passageiros fazem check-in e aguardam na fila de embarque. Crie TAD FilaEmbarque onde cada nó tem nome, assento e classe (Econômica, Executiva). Implemente enqueue, dequeue, isEmpty e imprimirFila() (lista todos os passageiros).
Escreva código para essas funções.
Simule cinco passageiros, exiba fila, faça dois dequeue() e exiba novamente.
4.6 Escalonamento de Processos (CPU Ready Queue)
Section titled “4.6 Escalonamento de Processos (CPU Ready Queue)”No sistema operacional, processos prontos para execução aguardam em uma fila. Modele Processo com pid e tempo_CPU. TAD ReadyQueue com enqueue, dequeue, peek e size. Código que roda num “loop”:
- Enquanto não isEmpty()
- remove próximo processo, executa por quantum, e se ainda não terminou, faz enqueue de volta.
Simule três processos e um quantum de 5ms.
4.7 Fila de Chamadas de Suporte (Help-desk)
Section titled “4.7 Fila de Chamadas de Suporte (Help-desk)”Chamados de suporte técnico entram em uma fila e são atendidos por ordem de chegada. Crie Chamado com ticket_id, descricao e usuario. Modele FilaSuporte com as operações básicas. Adicione método cancelar(ticket_id) que remove o chamado da fila (remoção genérica por índice). Pseudocódigo para cancelar, usando buscarPorId + removerPorPosicao.
Simule inserções, um cancelamento e exiba o estado final.
4.8 Fila Circular de Sensoriamento
Section titled “4.8 Fila Circular de Sensoriamento”Um sistema embarcado lê valores de sensor e os armazena num buffer circular de tamanho fixo antes de processar. Modele FilaCircularSensor com array de double e índices head, tail. Implemente enqueue, dequeue, isFull, isEmpty. Pseudocódigo do wrap-around dos índices ((i+1) mod capacidade).
Demonstre inserindo até encher, removendo dois, e inserindo mais dois.
4.9 Fila de Impressora em Ambiente Multiusuário
Section titled “4.9 Fila de Impressora em Ambiente Multiusuário”Em laboratório de informática, vários usuários mandam jobs para impressoras diferentes; cada impressora mantém sua própria fila. Modele Job com usuario, arquivo e pagina_inicio–pagina_fim. Crie FilaImpressora com enqueue, dequeue. Adicione priorizar(usuario) que remonta a fila, trazendo jobs desse usuário ao início (mantendo ordem relativa entre eles).
Pseudocódigo para priorizar:
- Percorre fila, extrai jobs do usuário, os salva em lista auxiliar, depois reconstrói fila com esses jobs na frente.