image

Acesse bootcamps ilimitados e +650 cursos pra sempre

60
%OFF
Article image
Fernando Araujo
Fernando Araujo07/10/2024 09:55
Compartilhe

<Direto ao Ponto 50> Estruturas de Dados - Filas

    Artigos desta série: ( < ) Anterior | Índice | Seguinte ( > )

     

    Olá, dev!

     

    Este é mais um artigo da série DIRETO AO PONTO, que eu estou escrevendo para a DIO. Ele vai tratar de uma das principais estruturas de dados, as filas.

     

    Sumário

    1. Introdução

    2. As filas

    3. Exemplos de aplicações implementadas com filas

    4. Considerações finais

    5. Referências

     

     

    1 – Introdução

     

    Eu criei a série de artigos DIRETO AO PONTO com o objetivo de apresentar, de forma simples e direta, conhecimentos básicos da programação e de computação, principalmente, para os iniciantes.

     

    Aqui, são tratados de temas como lógica de programação, linguagens, hardware dos computadores, história da computação e assuntos relacionados à plataforma da DIO, como a escrita de artigos e os desafios de código.

     

    Neste artigo, eu vou falar sobre as filas e as aplicações que usam filas na implementação. Dentre estas aplicações, estão os servidores de impressão e servidores web.

     


    2 – As filas

     

     image

    OBS: Recomendo assistir a essa animação divertida [1], do quadro mostrado na figura acima, sobre como as pessoas costumam se comportar em filas do nosso cotidiano (link nas referências).

     

    Da mesma forma que as listas, as filas também são um Tipo Abstrato de Dado (TAD), definição de um modelo matemático para tipos de dados. 

     

    Basicamente, um TAD especifica um conjunto de dados e as operações que podem ser realizadas sobre eles, sem tratar da implementação destas operações.

     

    Por exemplo, uma lista de tarefas permite adicionar, remover ou verificar tarefas da lista. O TAD define essas operações (adicionar, remover, verificar), mas não diz como a lista é armazenada ou como essas operações são realizadas internamente. Essa abstração permite que se use a lista sem se preocupar com os detalhes de implementação.

     

    Os TADs são modelos matemáticos que encapsulam dados e operações que podem ser realizadas sobre esses dados, como um objeto. Os mais comuns são:

    ·        Lista (List);

    ·        Fila (Queue);

    ·        Pilha (Stack);

    ·        Conjunto (Set);

    ·        Mapa (Map);

    ·        Dicionário (Dictionary);

    ·        Árvore (Tree);

    ·        Grafo (Graph).

      

    A estrutura de dados fila é usada para armazenar elementos de forma ordenada, seguindo o princípio FIFO (“First In, First Out”), ou seja, o primeiro elemento a entrar é o primeiro a sair.

     

    Este comportamento é útil em várias situações, para gerenciar tarefas em ordem sequencial. Algumas aplicações são listadas a seguir:

    ·        Sistemas de impressão: Gerenciamento de trabalhos de impressão por ordem de chegada;

    ·        Servidores web: Processamento de requisições HTTP;

    ·        Sistemas operacionais: Gerenciamento de processos em sistemas multitarefa.

    ·        Algoritmos de busca em grafos: Implementação de algoritmos como BFS (Busca em Largura).

    ·        Filas de mensagens: Comunicação entre diferentes partes de um sistema distribuído.

     

     

    Uma fila possui as seguintes características, algumas a diferem claramente de uma lista:

    ·        Uma variável aponta para o primeiro elemento da fila;

    ·        Outra aponta para o último elemento;

    ·        Cada elemento aponta apenas para o próximo da fila (semelhante a uma lista simplesmente encadeada);

    ·        A fila só pode ser varrida a partir do primeiro elemento, indo até o último;

    ·        Um elemento só pode ser inserido na fila na última posição;

    ·        Só o primeiro elemento da fila pode ser removido;

     

     

    Veja que ela uma fila se comporta como uma lista simplesmente encadeada, com cada elemento apontando para o seguinte. Além disso, ela se comporta como uma lista duplamente encadeada, pois uma segunda variável aponta para o último elemento, embora ela não possa ser percorrida de trás para a frente.

     

    As operações básicas que podem ser realizadas com uma fila são (em pseudo-código, independentemente de alguma linguagem de programação específica:

     

    Criação (ou declaração) – nomeia a variável, informa o tipo e reserva espaço para os elementos:

    int fila[10] – declara um vetor de inteiros com 10 posições

    int inicio - declara inteiro para o índice do primeiro elemento

    int fim - declara inteiro para o índice do novo elemento a inserir

     

    Inicialização – ao declarar a fila, já informar os elementos dela:

    int fila = [3, 4, 0, 1, -5, 23 ] – declara um vetor de inteiros com 6 posições

    int inicio = -1 - declara inteiro com o índice (-1, nulo) do primeiro elemento

    int fim = 0 - declara inteiro com índice (0) da posição de inserção do próximo elemento

     

    Acesso – Só pode ser acessado o valor armazenado na primeira posição da fila, na operação de remoção do primeiro elemento:

    elemento = fila[inicio]; // na fila acima, o valor acessado é 3 (primeiro elemento)

    print(fila[inicio]) // imprime o valor 3, que era o primeiro elemento da fila acima

     

    Atribuição – não se pode atribuir um valor para nenhuma posição da fila. Além disso, novos elementos só podem ser inseridos no final da fila, após o último elemento presente, numa operação de inserção:

    fila[fim] = 9; // atribui o valor 9 à última posição da fila acima, que ficaria [4, 0, 1, -5, 23, 9 ].

     

    Fila vazia – Se a fila não possuir nenhum elemento armazenado, ela estará vazia e a operação de remoção não pode ser realizada.

    fila = [ ] – fila sem nenhum elemento (vazia)

     

    Fila cheia – Se a fila usar todo o espaço para inserção de elementos, ela estará cheia e a operação de inserção não pode ser realizada. Este caso pode ocorrer no caso estático de um vetor cheio ou, no caso dinâmico, sistema sem memória para alocação dinâmica.

    Para uma fila de 6 elementos, a fila [4, 0, 1, -5, 23, 9 ] está cheia, sem caber novos elementos.

     

    Listar elementos da fila (opcional) – Esta operação (opcional) varre todos os elementos da fila e os lista, seguindo do primeiro ao último elemento.

     

    Tamanho da fila (opcional) - Esta operação (opcional) varre todos os elementos da fila, contando quantos estão armazenados nela.

     

    Limpeza da fila (opcional) - Esta operação (opcional) limpa, de uma vez só, o conteúdo de todos os elementos do vetor para um valor considerado nulo (0, string vazio, null etc.).

      

    Uma fila pode ser implementada de várias maneiras: usando vetor estático, lista encadeada (com ponteiros), com um tipo lista (list) ou por um tipo específica (Queue). Vamos ver um resumo de cada uma delas.

     

    I - IMPLEMENTAÇÃO COM LISTA

     

    É semelhante àquela mostrada no artigo anterior, no qual eu detalhei o uso de listas.

     

    Uma fila só pode ser percorrida do início ao fim (como uma lista simplesmente encadeada) e um novo elemento só pode ser adicionado no final dela, além de só poder ser retirado o primeiro elemento da fila (ver figura a seguir, com a fila inicial).

    image

      

    A fila tem um ponteiro adicional que aponta para o seu elemento final, evitando que toda a fila precise ser percorrida até o elemento final para adicionar um novo elemento após ele. O ponteiro de final de fila já acessa o elemento final.

     

    Assim, para inserir um novo elemento, basta fazer o último elemento da fila apontar (campo prox) para o novo, o campo prox do novo elemento apontar para o valor nulo (indicando que agora ele é o final da fila) e atualizar a variável de final de fila, que apontará para o novo elemento, como novo último da fila.

     

    Se o ponteiro inicial apontar para o valor nulo, significa que a fila está vazia, sem nenhum elemento armazenado, esperando por um novo elemento para poder ser utilizada.

     

    Todo novo elemento será adicionado após o último elemento. Se ele for o primeiro da fila, o ponteiro de início da fila também deverá ser atualizado (ver figura).

     image

     

    Após a inserção do novo elemento, a fila ficaria assim:


    image


    Em uma fila, só o primeiro elemento poderá ser removido, significando que ele saiu para ser usado, passando o segundo elemento a ser o novo primeiro elemento da fila. Com base na figura da fila inicial, abaixo é mostrada a operação de remoção do primeiro elemento:

     

    image


    E a fila ficará assim:

     

    image

     

    OBS: na verdade, um elemento removido não é apagado, ele continua armazenado na estrutura do nó, no mesmo endereço alocado na sua criação, apenas não será mais acessado por nenhum ponteiro (campo prox) da fila.

     

     

    II - A IMPLEMENTAÇÃO COM VETOR ESTÁTICO

     

    Segue o modelo mostrado no artigo sobre vetores (anterior ao das listas), com diferenças que vou mostrar agora (ver figura da fila):

     

    image


    Basicamente, é preciso criar um vetor com um número determinado de posições, usar duas variáveis para determinar os índices do primeiro elemento da fila e da posição vaga onde deve ser armazenado um novo elemento. No início, uma fila que acabou de ser criada ficaria assim, vazia:

     

    image


    Cada inserção de um novo elemento será feita na posição indicada pelo índice da variável de final (fim) de fila, que será incrementada de 1 posição (ver figuras com a inserção do primeiro e de um segundo elemento).

     

    image

     

    image


    Cada remoção de elemento será feita na posição indicada pelo índice da variável de início de fila, que também será incrementada de 1. A figura a seguir mostra a fila após a remoção do elemento 8.

     

    image


    OBS: na verdade, um elemento removido não sai do vetor, ele continuará lá, na mesma posição, apenas não será mais acessado.

     

    Na figura anterior, removendo mais 1 elemento, a fila ficará vazia e nenhum elemento poderá ser removido. Veja que a variável de início agora aponta para o índice 2, não para 0. A situação de fila vazia pode ser identificada quando os valores das variáveis de início e fim da fila tiverem o mesmo valor.


    image

     

    Caso todas as posições do vetor sejam ocupadas, a fila estará cheia e não aceitará mais inserções de elementos. A partir da situação da fila da figura anterior, inserindo mais 4 elementos, ela ficaria cheia, assim:

     

     image

     

    Veja que a fila da figura anterior está cheia, mas ainda existem 2 posições iniciais vazias, que poderiam ser aproveitadas. Para isso, seria preciso trocar todos os elementos de posição, uma operação custosa.

     

    O uso de filas implementadas por vetores só é eficiente quando o vetor é bem maior que a quantidade de elementos que serão inseridos na fila, assim ela não ficaria cheia regularmente, o que evitaria a operação de trocas de posição para aproveitamento das posições vazias.

     

    Mesmo assim, filas implementadas com vetores são muito simples e didáticas para um ensino inicial do tema.

     

    FILA CIRCULAR

     

    Uma solução criada para evitar muitas posições vazias é a fila circular. Ela junta o final do vetor com seu início, gerando um círculo de posições que se complementam, permitindo que um elemento novo volte a ser inserido no início da fila original. Assim, as posições vagas no início da fila são aproveitadas, a partir da realocação das variáveis de início e fim da fila.


    A fila da figura anterior poderia ser representada por uma fila circular da seguinte maneira:

     

     image

     

    Na fila da figura anterior, o início da fila aponta para a posição de índice 2, enquanto o final da fila aponta para a próxima posição vaga (6, inexistente);

     

    A solução encontrada é apontar o fim da fila para a posição 0 do vetor, criando uma fila circular, mostrada na figura seguinte:

     

    image


    Por exemplo, para inserir um novo elemento (12) na fila, ela (a fila circular) e o vetor correspondente ficariam assim:

     

    image


    Desta forma, a implementação de uma fila circular melhora a da fila com vetor estático, pois aproveita as posições já usadas nas remoções. Mesmo assim, o uso de vetor para implementar filas é muito limitado.

     

     

    III - A IMPLEMENTAÇÃO USANDO A ESTRUTURA LIST

     

    Uma fila implementada com listas segue as seguintes características:

     

    Uma lista pode ser criada sem nenhum elemento, significando uma fila vazia.

    Ex: fila = [ ]

     

    A operação de atribuição de um valor (ou inserção de um elemento) na fila se dá sempre na última posição da lista. Em Python, o método seria append():

    para lista = [ 8, -1, 4, 25, 0]:

    Ex: list.append(7) insere o valor 7 na última posição, ficando [ 8, -1, 4, 25, 0, 7].

     

    Já a operação de acesso a um valor (ou remoção de um elemento) da fila se dá sempre na primeira posição da lista. Em Python, o método é pop(0).

    Ex: para lista = [ 8, -1, 4, 25, 0, 7 ], list.pop(0) exclui o valor (8) da primeira posição resultando em [ -1, 4, 25, 0, 7 ]

     


    A figura a seguir mostra a fila indicada acima após a inserção do 7 e a remoção do 8:

     

     image

     

     

    IV - IMPLEMENTAÇÃO USANDO UM TIPO ESPECÍFICO PARA FILA

     

    Segue as seguintes características:

     

    Algumas linguagens oferecem um tipo específico para tratar de filas (queues), com pelo menos 2 métodos para inserir e remover elementos.

     

    Por exemplo, a linguagem C# oferece o tipo Queue<T>, com os métodos:

     

    ·        Enqueue( ), para adicionar um elemento (enfileirar) no final da fila;

    • Dequeue( ), para remover primeiro elemento da fila (desenfileirar).

     

    O tipo Queue<T> ainda oferece outros métodos específicos para manipulação de filas:

    ·        Peek() - Retorna o primeiro elemento da fila sem removê-lo;

    ·        Clear() - Remove todos os elementos da fila, deixando-a vazia;

    ·        Contains(itemT) - Verifica se a fila contém o elemento especificado;

    ·        ToArray() - Converte a fila em array com os elementos, na ordem;

    ·        TrimExcess() - Reduz a capacidade da fila para o número real de elementos, liberando memória;

    ·        GetEnumerator() - Retorna um enumerador para percorrer os elementos da fila;

    ·        Count – Propriedade que retorna o número total de elementos da fila.

     

     

    3 – Exemplos de aplicações implementadas com fila

     

    A seguir, seguem alguns programas básicos que implementam filas, em linguagens diferentes:

     

     

    NA LINGUAGEM PASCAL – USANDO VETOR ESTÁTICO

     

    program FilaComVetor;
     
    const
     MAX = 4; { Tamanho máximo da fila }
     
    type
     TFila = array[1..MAX] of Integer;
     
    var
     fila: TFila;
     inicio, fim: Integer; { variáveis para início e final da fila }
     
    { Função para inicializar a fila }
    procedure InicializarFila;
    begin
     inicio := 1;
     fim := 0;
    end;
     
    { Função para verificar se a fila está vazia }
    function FilaVazia: Boolean;
    begin
     FilaVazia := (fim < inicio);
    end;
     
    { Função para verificar se a fila está cheia }
    function FilaCheia: Boolean;
    begin
     FilaCheia := (fim = MAX);
    end;
     
    { Procedimento para enfileirar um elemento na fila }
    procedure Enfileirar(elemento: Integer);
    begin
     if FilaCheia then
         writeln('A fila está cheia. Não foi possível adicionar ', elemento)
     else
     begin
         fim := fim + 1;
         fila[fim] := elemento;
         writeln(elemento, ' foi adicionado à fila.');
     end;
    end;
     
    { Função para desenfileirar (remover) um elemento da fila }
    function Desenfileirar: Integer;
    var
     removido: Integer;
    begin
     if FilaVazia then
     begin
         writeln('A fila está vazia. Não há elementos para remover.');
         Desenfileirar := -1; { Retorna -1 para indicar erro }
     end
     else
     begin
         removido := fila[inicio];
         writeln(removido, ' foi removido da fila.');
         inicio := inicio + 1;
         Desenfileirar := removido;
     end;
    end;
     
    { Procedimento para exibir o estado atual da fila }
    procedure MostrarFila;
    var
     i: Integer;
    begin
     if FilaVazia then
         writeln('A fila está vazia.')
     else
     begin
         writeln('Fila atual: ');
         for i := inicio to fim do
             write(fila[i], ' ');
         writeln;
     end;
    end;
     
    { Programa principal }
    begin
     InicializarFila; { Inicializa a fila }
     
     { Exemplo de operações na fila }
     Enfileirar(10);
     Enfileirar(20);
     Enfileirar(30);
     
     MostrarFila; { Mostra a fila }
     
     Desenfileirar; { Remove o primeiro elemento }
     Desenfileirar; { Remove o segundo elemento }
     
     MostrarFila; { Mostra a fila }
     
     Enfileirar(40); { Tenta adicionar um novo elemento }
     MostrarFila; { Exibe o estado final da fila }
     
     Enfileirar(50); { Tenta adicionar um novo elemento }
     MostrarFila; { Exibe o estado final da fila }
     
    end.
    

     

     Saída do programa

     

    10 foi adicionado à fila.

    20 foi adicionado à fila.

    30 foi adicionado à fila.

    Fila atual:

    10 20 30

    10 foi removido da fila.

    20 foi removido da fila.

    Fila atual:

    30

    40 foi adicionado à fila.

    Fila atual:

    30 40

    A fila está cheia. Não foi possível adicionar 50

    Fila atual:

    30 40

      

     

    LINGUAGEM C – USANDO LISTA ENCADEADA COM PONTEIROS

     

    #include <stdio.h>
    #include <stdlib.h>
     
    // Definição do nó da fila
    struct No {
     int dado;
     struct No* prox;
    };
     
    // Estrutura da fila, com ponteiros para o início (inic) e final (fim)
    struct Queue {
     struct No* inicio;
     struct No* fim;
    };
     
    // Função para criar uma nova fila vazia
    struct Queue* criarFila() {
     struct Queue* fila = (struct Queue*)malloc(sizeof(struct Queue));
     fila->inicio = fila->fim = NULL;
     return fila;
    }
     
    // Função para criar um novo nó
    struct No* novoNo(int valor) {
     struct No* temp = (struct No*)malloc(sizeof(struct No));
     temp->dado = valor;
     temp->prox = NULL;
     return temp;
    }
     
    // Função para enfileirar (inserir) um elemento
    void enfileirar(struct Queue* fila, int valor) {
     // Cria um novo nó
     struct No* temp = novoNo(valor);
     
     // Se a fila estiver vazia, o novo nó será o início e o final
     if (fila->fim == NULL) {
         fila->inicio = fila->fim = temp;
         printf("%d foi adicionado à fila.\n", valor);
         return;
     }
     
     // Adiciona o novo nó no final da fila e atualiza o ponteiro 'rear'
     fila->fim->prox = temp;
     fila->fim = temp;
     printf("%d foi adicionado à fila.\n", valor);
    }
     
    // Função para desenfileirar (remover) um elemento da fila
    int desenfileirar(struct Queue* fila) {
     // Se a fila estiver vazia, retorna um valor inválido
     if (fila->inicio == NULL) {
         printf("A fila está vazia. Não é possível remover elementos.\n");
         return -1;
     }
     
     // Armazena o ponteiro do início da fila
     struct No* temp = fila->inicio;
     int removido = temp->dado;
     
     // Move o ponteiro 'front' para o próximo nó
     fila->inicio = fila->inicio->prox;
     
     // Se o 'front' se tornar NULL, a fila está vazia, então atualiza 'rear' também
     if (fila->inicio == NULL) {
         fila->fim = NULL;
     }
     
     // Libera o nó removido
     free(temp);
     printf("%d foi removido da fila.\n", removido);
     return removido;
    }
     
    // Função para verificar o próximo elemento da fila
    int verificar(struct Queue* fila) {
     if (fila->inicio == NULL) {
         printf("A fila está vazia.\n");
         return -1;
     } else {
         printf("O próximo elemento é: %d\n", fila->inicio->dado);
         return fila->inicio->dado;
     }
    }
     
    // Função para verificar se a fila está vazia
    int filaVazia(struct Queue* fila) {
     return fila->inicio == NULL;
    }
     
    // Função para exibir o estado atual da fila
    void mostrarFila(struct Queue* fila) {
     if (filaVazia(fila)) {
         printf("A fila está vazia.\n");
     } else {
         struct No* temp = fila->inicio;
         printf("Fila atual: ");
         while (temp != NULL) {
             printf("%d ", temp->dado);
             temp = temp->prox;
         }
         printf("\n");
     }
    }
     
    // Programa principal
    int main() {
     // Cria uma nova fila
     struct Queue* minhaFila = criarFila();
     
     // Exemplo de uso da fila
     enfileirar(minhaFila, 10); // Adiciona 10 à fila
     enfileirar(minhaFila, 20); // Adiciona 20 à fila
     enfileirar(minhaFila, 30); // Adiciona 30 à fila
     
     mostrarFila(minhaFila);    // Exibe a fila
     
     verificar(minhaFila);         // Verifica o próximo elemento
     
     desenfileirar(minhaFila);  // Remove 10 da fila
     desenfileirar(minhaFila);  // Remove 20 da fila
     
     mostrarFila(minhaFila);    // Exibe a fila após remoções
     
     desenfileirar(minhaFila);  // Remove 30 da fila
     
     mostrarFila(minhaFila);    // Exibe a fila final
     
     // Libera a fila ao final do programa
     free(minhaFila);
     
     return 0;
    }
    

     

    Saída do programa

     

    10 foi adicionado à fila.

    20 foi adicionado à fila.

    30 foi adicionado à fila.

    Fila atual: 10 20 30

    O próximo elemento é: 10

    10 foi removido da fila.

    20 foi removido da fila.

    Fila atual: 30

    30 foi removido da fila.

    A fila está vazia.

     

     

    NA LINGUAGEM PYTHON – USANDO O TIPO LIST

     

    # Lista para armazenar os elementos da fila
    fila = [ ]
     
    # Função para adicionar um elemento à fila)
    def enfileirar(elemento):
     fila.append(elemento)
     print(f"{elemento} foi adicionado à fila.")
     
    # Função para remover o primeiro elemento da fila)
    def desenfileirar():
     if fila_vazia():
         print("A fila está vazia. Não é possível remover elementos.")
         return None
     else:
         elemento_removido = fila.pop(0) # Remove o primeiro elemento
         print(f"{elemento_removido} foi removido da fila.")
         return elemento_removido
     
    # Função para verificar o primeiro elemento da fila (sem remover)
    def verificar_fila():
     if fila_vazia():
         print("A fila está vazia.")
         return None
     else:
         print(f"O próximo elemento é: {fila[0]}")
         return fila[0]
     
    # Função para verificar se a fila está vazia
    def fila_vazia():
     return len(fila) == 0
     
    # Função para exibir o estado atual da fila
    def mostrar_fila():
     if fila_vazia():
         print("A fila está vazia.")
     else:
         print(f"Fila atual: {fila}")
     
    # Exemplo de uso da fila
    enfileirar(10) # Adiciona 10 à fila
    enfileirar(20) # Adiciona 20 à fila
    enfileirar(30) # Adiciona 30 à fila
     
    mostrar_fila() # Exibe a fila atual
     
    verificar_fila() # Verifica o primeiro elemento (10)
     
    desenfileirar() # Remove 10 da fila
    desenfileirar() # Remove 20 da fila
     
    mostrar_fila() # Exibe a fila após remoções
     
    desenfileirar() # Remove 30 da fila
    desenfileirar() # Tenta remover de uma fila vazia
    

     

    Saída

     

    10 foi adicionado à fila.

    20 foi adicionado à fila.

    30 foi adicionado à fila.

    Fila atual: [10, 20, 30]

    O próximo elemento é: 10

    10 foi removido da fila.

    20 foi removido da fila.

    Fila atual: [30]

    30 foi removido da fila.

    A fila está vazia. Não é possível remover elementos.

      

     

    LINGUAGEM C# – USANDO O TIPO ESPECÍFICO QUEUE<T>

     

    using System;
    using System.Collections.Generic;
     
    class Program
    {
     static void Main()
     {
         // Criação da fila usando Queue<int>
         Queue<int> fila = new Queue<int>();
     
         // Enfileirar elementos
         Enfileirar(fila, 10); // Adiciona 10 à fila
         Enfileirar(fila, 20); // Adiciona 20 à fila
         Enfileirar(fila, 30); // Adiciona 30 à fila
     
         // Mostrar estado atual da fila
         MostrarFila(fila);    // Exibe a fila atual
     
         // Verificar o próximo elemento
         Verificar(fila);         // Verifica o primeiro elemento (10)
     
         // Desenfileirar elementos
         Desenfileirar(fila);  // Remove 10 da fila
         Desenfileirar(fila);  // Remove 20 da fila
     
         // Mostrar estado atual da fila
         MostrarFila(fila);    // Exibe a fila após remoções
     
         // Desenfileirar o restante e verificar fila vazia
         Desenfileirar(fila);  // Remove 30 da fila
         Desenfileirar(fila);  // Tenta remover de uma fila vazia
     }
     
     // Função para enfileirar um elemento
     static void Enfileirar(Queue<int> fila, int elemento)
     {
         fila.Enqueue(elemento);
         Console.WriteLine($"{elemento} foi adicionado à fila.");
     }
     
     // Função para desenfileirar um elemento
     static void Desenfileirar(Queue<int> fila)
     {
         if (fila.Count == 0)
         {
             Console.WriteLine("A fila está vazia. Não é possível remover elementos.");
         }
         else
         {
             int elementoRemovido = fila.Dequeue(); // Remove o primeiro elemento
             Console.WriteLine($"{elementoRemovido} foi removido da fila.");
         }
     }
     
     // Função para verificar o próximo elemento da fila
     static void Verificar(Queue<int> fila)
     {
         if (fila.Count == 0)
         {
             Console.WriteLine("A fila está vazia.");
         }
         else
         {
             Console.WriteLine($"O próximo elemento é: {fila.Peek()}");
         }
     }
     
     // Função para mostrar o estado atual da fila
     static void MostrarFila(Queue<int> fila)
     {
         if (fila.Count == 0)
         {
             Console.WriteLine("A fila está vazia.");
         }
         else
         {
             Console.Write("Fila atual: ");
             foreach (int item in fila)
             {
                 Console.Write(item + " ");
             }
             Console.WriteLine();
         }
     }
    }
    

     

    Saída

     

    10 foi adicionado à fila.

    20 foi adicionado à fila.

    30 foi adicionado à fila.

    Fila atual: 10 20 30

    O próximo elemento é: 10

    10 foi removido da fila.

    20 foi removido da fila.

    Fila atual: 30

    30 foi removido da fila.

    A fila está vazia. Não é possível remover elementos.

     

     

    4 – Considerações finais

     

    Este é mais um artigo da série DIRETO AO PONTO, que eu estou escrevendo para a DIO. Neste artigo eu tratei das filas, mais um Tipo Abstrato de Dado (TAD), juntamente com as listas e pilhas.

     

    Uma fila é uma estrutura de dados, como a lista, usada para armazenar elementos de forma ordenada, mas com características de inserção e remoção de elementos. Ela segue o princípio FIFO (“First In, First Out”), no qual o primeiro elemento a entrar é o primeiro a sair.

     

    Elas são apropriadas em aplicações para gerenciar tarefas em ordem sequencial, como em sistemas de impressão, servidores web ou no gerenciamento de processos em sistemas operacionais.

     

    Uma fila pode ser implementada de várias formas, usando vetores estáticos, ponteiros, listas ou estruturas específicas para manipulação de filas, como Queue<T>, da linguagem C#.

     

    Algumas destas formas são bem antigas (vetores), mas continuam em uso por serem muito didáticas, principalmente para os iniciantes em programação, já outras são bem trabalhosas (com ponteiros), pois exigem completo gerenciamento da memória pelo programador.

     

    As formas mais atuais de implementação são usando listas (como em Python) ou estruturas específicas, como a classe Queue<T>, por exemplo.

     

    Neste artigo, foram mostrados os detalhes dos conceitos e das operações usadas para a implementação de filas usando vetores e ponteiros.

     

    Também foram apresentados exemplos de códigos com a implementação de filas usando cada uma das 4 formas citadas anteriormente.

     

    No próximo artigo, vamos falar das pilhas, muito usadas na programação.


     

     

    5 – Referências

     

    Praticamente todo o conteúdo deste artigo foi tirado do que eu aprendi (e me lembro) sobre o assunto desde o início da minha carreira como programador, desde os anos 80 até agora. Algumas atualizações conceituais foram feitas com a ajuda do ChatGPT e do Copilot.


    Para criar os códigos dos exemplos, eu consultei o ChatGPT e fiz algumas correções necessárias para sair do jeito que eu queria. Todos os códigos foram testados e rodaram sem problemas.

     

    [1] - Ferdinand Lutz. Stay in Queue. Disponível em <https://www.youtube.com/watch?v=IPxBKxU8GIQ>. Acessado em: 05/10/2024.

     

     

    Artigos desta série: ( < ) Anterior | Índice | Seguinte ( > )

    Compartilhe
    Comentários (2)
    Fernando Araujo
    Fernando Araujo - 07/10/2024 14:01

    Obrigado, Regilene!

    Leia os últimos 5 artigos anteriores sobre estruturas de dados que complementam esse.

    Regilene Silva
    Regilene Silva - 07/10/2024 13:58

    Já salvei aqui para ler com calma mais tarde! :)