Estruturas de Dados 1 – Min/Max Queue

Aula por Lúcio Cardoso

A estrutura de dados Min Queue é uma adaptação da queue do C++. Nela, podemos realizar as seguintes operações:

  • Adicionar um elemento de valor $$v$$ atrás da fila
  • Remover o elemento da frente da fila
  • Responder qual o elemento de menor valor presente na fila

Descrição da Estrutura

Para armazenar as informações da estrutura, utilizaremos um deque. O deque é uma estrutura semelhante à queue, com a diferença de que podemos inserir/remover elementos dos dois lados da fila.

Em particular, cada posição do deque guardará um par de valores: O valor do elemento e o tempo em que foi adicionado (o primeiro elemento adicionado foi adicionado no tempo 1, e assim sucessivamente).

Função $$push(v)$$

A função $$push(v)$$ insere um elemento de valor $$v$$ na parte de trás da fila.

Seja $$v_0$$ o elemento atual no fundo da fila. Se $$v_0 \geq v$$, do momento em que $$v$$ foi adicionado em diante, $$v_0$$ nunca será o valor mínimo na estrutura, pois $$v$$ é menor e, por estar atrás de $$v_0$$, será removido em algum tempo depois de $$v_0$$. Logo, antes de adicionar $$v$$, iremos remover todos os elementos $$v_0$$ do fundo da fila enquanto $$v_0 \geq v$$. Após isso, vamos inserir o par $$(v, tempo)$$ no fundo do deque.

Perceba que, dessa forma, a Min Queue estará sempre ordenada de maneira crescente, e, por tanto, o menor elemento na estrutura será sempre o elemento na frente da fila. Agora, como removemos elementos da estrutura, precisamos de um cuidado adicional na função $$pop()$$.

Função $$pop()$$

A função $$pop()$$ remove o elemento presente na frente da fila.

Perceba que, na função $$push()$$, removemos elementos do fundo da fila, e portanto, é possível que o elemento que deveria estar na frente da fila ao executarmos o comando $$pop()$$ já tenha sido removido.

Para conferir isto, iremos guardar duas variáveis fora da estrutura: $$l$$ e $$r$$. Estas variáveis indicam, respectivamente, o tempo em que o elemento na frente da fila foi inserido (mesmo se este já foi removido) e o tempo em que será adicionado o próximo elemento no fundo na fila. Assim, é muito simples remover um elemento: Basta checar se o tempo do elemento na frente do deque é igual a $$l$$. Se sim, removemos ele, senão, o elemento da frente já foi removido antes e não fazemos nada.

Para atualizar as variáveis $$l$$ e $$r$$, basta somar um no valor de $$r$$ cada vez que adicionarmos um elemento com a função $$push()$$ e somar um em $$l$$ a cada vez que removemos um elemento da frente da fila.

Função $$getmin()$$

A função $$getmin()$$ retorna o elemento de menor valor presente na fila.

Como já dito anteriormente, a estrutura foi mantida de tal forma que o elemento mínimo será aquele na frente da fila. Logo, para retornar o menor elemento, basta retornamos o valor do elemento na frente do deque.

Complexidade

Inicialmente, sabemos que as funções $$getmin()$$ e $$pop()$$ possuem complexidade $$O(1)$$. Além disso, cada elemento da estrutura foi removido/adicionado no máximo uma vez. Logo, a complexidade final após todas as operações terem sido realizadas será $$O(n)$$, onde $$n$$ é o tamanho da fila. Assim, dizemos que cada operação $$push()$$ terá complexidade amortizada $$O(1)$$.

Confira o código final da Min Queue, para melhor entendimento:


// Curso Noic de Informática – Estruturas de Dados 11
// Minqueue – Complexidade O(1) amortizada
// A Minqueue pode facilmente ser adaptada para Maxqueue, respondendo
// o valor máximo na estrutura
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
struct MinQueue
{
deque<pii> dq;
int l, r;
// inicialmente, dizemos que l = r = 1
void init(void)
{
l = r = 1;
dq.clear();
}
// adiciona v atrás da fila
void push(int v)
{
while (!dq.empty() && v < dq.back().ff) dq.pop_back();
dq.push({v, r}); // inserimos v com tempo r
r++; // aumentamos o tempo r
}
// remove o elemento da frente da fila
void pop(void)
{
if (!dq.empty() && dq.front().ss == l) dq.pop_front();
l++; //aumentamos o tempo l
}
int getmin(void) {return dq.front().ff;} // retorna o valor mínimo da estrutura
};

view raw

noic-ds11.cpp

hosted with ❤ by GitHub