Módulo 14 - Performance e profiling
Estruturas eficientes: deque, heapq e bisect
10 min de leitura · por Cesar Gargiulo, revisado pela equipe ValorFinal e GuardiaSec · Atualizado em 01/07/2026
O que você vai aprender
- Usar collections.deque para filas com inserção e remoção O(1) nas pontas.
- Usar heapq para manter e retirar o menor elemento com eficiência.
- Usar bisect para inserir e buscar em listas ordenadas.
- Escolher a estrutura especializada certa para cada padrão de uso.
Ouvir o resumo desta aula
Um recap de cerca de 2 minutos na voz do Valim, para ouvir no trânsito ou na academia.
Ler a transcrição do resumo
Resumo da aula: Estruturas eficientes: deque, heapq e bisect.
Os objetivos desta aula. Usar collections.deque para filas com inserção e remoção O(1) nas pontas. Usar heapq para manter e retirar o menor elemento com eficiência. Usar bisect para inserir e buscar em listas ordenadas. Escolher a estrutura especializada certa para cada padrão de uso.
Veja o essencial, parte por parte.
deque: filas rápidas nas duas pontas. deque adiciona e remove nas duas pontas em O(1).
heapq: o menor elemento sempre à mão. Você precisa repetidamente do menor (ou maior) elemento de uma coleção que muda.
bisect: listas ordenadas sem reordenar. Quando você mantém uma lista já ordenada e quer inserir um novo valor no lugar certo, ou descobrir onde ele se encaixaria, ordenar de novo a cada inserção é desperdício.
Esse foi o resumo do essencial. Para se aprofundar, leia a aula completa e responda os exercícios.
deque: filas rápidas nas duas pontas
A lista do Python é excelente no fim: adicionar com append e remover com pop na última posição são O(1). O problema é o começo. Inserir ou remover no início de uma lista obriga o Python a deslocar todos os outros itens uma casa, o que é O(n). Se o seu programa trata a coleção como uma fila, tirando do início e pondo no fim, a lista vira um gargalo silencioso. A collections.deque foi feita exatamente para isso: uma fila de duas pontas em que adicionar e remover em qualquer extremidade custa O(1).
from collections import deque
fila = deque(["ana", "bruno", "carla"])
fila.append("davi") # entra no fim, O(1)
primeiro = fila.popleft() # sai do inicio, O(1)
print(primeiro) # ana
print(fila) # deque(["bruno", "carla", "davi"])
# A deque tambem serve de janela deslizante com tamanho fixo
ultimos = deque(maxlen=3)
for n in range(6):
ultimos.append(n)
print(list(ultimos)) # [3, 4, 5]: so os tres ultimospopleft e append na deque são O(1); com maxlen ela vira uma janela dos últimos itens.
O recurso do maxlen merece destaque. Ao criar uma deque com tamanho máximo, ela descarta sozinha o item mais antigo quando um novo entra. Isso resolve com elegância problemas como manter os últimos registros, uma média móvel ou um histórico limitado, sem você precisar cortar a lista manualmente a cada passo. É o tipo de detalhe que troca várias linhas de código por uma escolha de estrutura.
heapq: o menor elemento sempre à mão
Imagine que você processa tarefas por prioridade e sempre precisa da mais urgente, ou que quer os cinco maiores de uma sequência enorme. Ordenar a coleção inteira a cada consulta é caro. O módulo heapq mantém os dados como um heap, uma organização em que o menor elemento fica sempre no topo, acessível de imediato. Inserir um novo item e retirar o menor são operações eficientes, sem reordenar tudo. O heap vive numa lista comum, e o heapq oferece as funções para manipulá-la corretamente.
import heapq
tarefas = []
heapq.heappush(tarefas, (2, "responder email"))
heapq.heappush(tarefas, (1, "corrigir bug critico"))
heapq.heappush(tarefas, (3, "revisar documento"))
# heappop sempre devolve a menor prioridade primeiro
prioridade, tarefa = heapq.heappop(tarefas)
print(prioridade, tarefa) # 1 corrigir bug critico
# Os tres maiores de uma sequencia, sem ordenar tudo
numeros = [8, 3, 15, 1, 9, 22, 4]
print(heapq.nlargest(3, numeros)) # [22, 15, 9]O heap entrega o menor com heappop; nlargest e nsmallest evitam ordenar a coleção inteira.
bisect: listas ordenadas sem reordenar
Quando você mantém uma lista já ordenada e quer inserir um novo valor no lugar certo, ou descobrir onde ele se encaixaria, ordenar de novo a cada inserção é desperdício. O módulo bisect faz uma busca binária: em vez de varrer a lista, ele divide o intervalo pela metade a cada passo e acha a posição correta em tempo O(log n), muito mais rápido que O(n). A função bisect encontra o ponto de inserção; a insort insere já mantendo a ordem. É a ferramenta certa para rankings, faixas e tabelas de corte ordenadas.
import bisect
notas = [50, 62, 70, 85, 91] # ja ordenada
# Onde entraria a nota 75, mantendo a ordem?
pos = bisect.bisect(notas, 75)
print(pos) # 3
bisect.insort(notas, 75) # insere no lugar certo
print(notas) # [50, 62, 70, 75, 85, 91]
# Classificar uma nota em faixas de conceito com busca binaria
cortes = [50, 70, 90]
conceitos = ["D", "C", "B", "A"]
print(conceitos[bisect.bisect(cortes, 84)]) # Bbisect acha a posição por busca binária; insort insere mantendo a lista ordenada.
O último exemplo mostra um uso elegante do bisect que muita gente não conhece: classificar um valor em faixas. Em vez de uma cadeia longa de if e elif comparando limites, você guarda os cortes ordenados e deixa a busca binária dizer em qual faixa o valor cai. O código fica menor, mais rápido e mais fácil de manter, porque adicionar uma faixa nova é só acrescentar um corte e um rótulo. É o espírito deste módulo: a estrutura certa não só acelera, ela simplifica.
Teste rápido
Por que usar deque em vez de lista para uma fila que remove do início?
Perguntas frequentes
- Quando prefiro deque em vez de lista?
- Sempre que você adiciona ou remove no início com frequência, como em filas e janelas deslizantes. Na lista essas operações são O(n); na deque são O(1). Se você só mexe no fim, a lista já é eficiente e não precisa trocar.
- heapq mantém a lista toda ordenada?
- Não. O heap garante apenas que o menor elemento está no topo, acessível de imediato. O resto não fica em ordem completa. É justamente por não ordenar tudo que inserir e retirar o menor saem baratos. Se você precisa da ordenação completa, use sorted.
- Como faço uma fila de prioridade com heapq?
- Empurre tuplas no formato (prioridade, item) com heappush. O heapq compara pela primeira posição, então heappop sempre devolve o item de menor prioridade numérica primeiro. Para prioridade inversa, use o valor negativo ou as funções nlargest e nsmallest.
- bisect funciona em lista não ordenada?
- Não corretamente. A busca binária do bisect pressupõe que a lista já está ordenada; ela divide o intervalo pela metade assumindo a ordem. Em uma lista bagunçada, o resultado não faz sentido. Mantenha a lista ordenada, inserindo sempre com insort.
- Essas estruturas exigem instalar algo?
- Não. deque vem em collections, e heapq e bisect são módulos da biblioteca padrão. Basta importar. É um dos grandes trunfos do Python: muita eficiência já vem incluída, sem dependência externa, para quem sabe qual módulo usar.
Fontes
Seu progresso fica salvo neste aparelho. Assinantes sincronizam entre os aparelhos.