Busca Binaria em Python: Como Implementar e Quando Usar

7 min de leitura Atualizado em 27 Apr 2026

O que e Busca Binaria?

Busca binaria e um dos algoritmos mais eficientes para encontrar um elemento em uma colecao ordenada. Em vez de verificar cada elemento um por um (busca linear, O(n)), a busca binaria divide a colecao ao meio a cada passo, alcancando complexidade O(log n).

Na pratica, isso significa que em uma lista com 1 milhao de elementos, a busca binaria precisa de no maximo 20 comparacoes para encontrar qualquer elemento — contra ate 1 milhao na busca linear.

Antes de comecar, certifique-se de dominar listas em Python e entender algoritmos de ordenacao, ja que busca binaria exige dados ordenados.


Busca Linear vs Busca Binaria

Para entender por que busca binaria e tao poderosa, vamos comparar:

Busca Linear

def busca_linear(lista, alvo):
    for i, elemento in enumerate(lista):
        if elemento == alvo:
            return i
    return -1

# Verifica cada elemento, um por um
numeros = list(range(1, 1_000_001))
resultado = busca_linear(numeros, 999_999)
# Precisa verificar 999.999 elementos!

Busca Binaria

def busca_binaria(lista, alvo):
    esquerda = 0
    direita = len(lista) - 1

    while esquerda <= direita:
        meio = (esquerda + direita) // 2

        if lista[meio] == alvo:
            return meio
        elif lista[meio] < alvo:
            esquerda = meio + 1
        else:
            direita = meio - 1

    return -1

# Divide ao meio a cada passo
numeros = list(range(1, 1_000_001))
resultado = busca_binaria(numeros, 999_999)
# Precisa de apenas ~20 comparacoes!

Comparacao de Performance

ListaBusca LinearBusca Binaria
100 elementosate 100 passosate 7 passos
1.000 elementosate 1.000 passosate 10 passos
1.000.000 elementosate 1.000.000 passosate 20 passos
1.000.000.000 elementosate 1 bilhao passosate 30 passos

Implementacao Iterativa

A versao iterativa e a mais usada na pratica por ser mais eficiente em memoria (sem overhead de recursao):

def busca_binaria(lista, alvo):
    """
    Busca binaria iterativa.
    Retorna o indice do elemento ou -1 se nao encontrado.
    """
    esquerda = 0
    direita = len(lista) - 1

    while esquerda <= direita:
        meio = (esquerda + direita) // 2
        valor_meio = lista[meio]

        if valor_meio == alvo:
            return meio
        elif valor_meio < alvo:
            # Alvo esta na metade direita
            esquerda = meio + 1
        else:
            # Alvo esta na metade esquerda
            direita = meio - 1

    return -1  # Nao encontrado

# Uso
numeros = [2, 5, 8, 12, 16, 23, 38, 56, 72, 91]

print(busca_binaria(numeros, 23))   # 5
print(busca_binaria(numeros, 50))   # -1
print(busca_binaria(numeros, 2))    # 0
print(busca_binaria(numeros, 91))   # 9

Como Funciona Passo a Passo

Buscando o valor 23 em [2, 5, 8, 12, 16, 23, 38, 56, 72, 91]:

PassoEsquerdaDireitaMeioValorAcao
10941616 < 23 → esquerda = 5
25975656 > 23 → direita = 6
356523Encontrado no indice 5

Apenas 3 passos para encontrar o elemento em uma lista de 10 elementos.


Implementacao Recursiva

A versao recursiva e mais elegante e facil de entender, porem usa mais memoria por causa da pilha de chamadas:

def busca_binaria_recursiva(lista, alvo, esquerda=0, direita=None):
    """
    Busca binaria recursiva.
    Retorna o indice do elemento ou -1 se nao encontrado.
    """
    if direita is None:
        direita = len(lista) - 1

    # Caso base: elemento nao encontrado
    if esquerda > direita:
        return -1

    meio = (esquerda + direita) // 2

    if lista[meio] == alvo:
        return meio
    elif lista[meio] < alvo:
        return busca_binaria_recursiva(lista, alvo, meio + 1, direita)
    else:
        return busca_binaria_recursiva(lista, alvo, esquerda, meio - 1)

# Uso
numeros = [2, 5, 8, 12, 16, 23, 38, 56, 72, 91]
print(busca_binaria_recursiva(numeros, 23))  # 5

Atencao: Python tem um limite de recursao padrao de 1000 (configuravel com sys.setrecursionlimit()). Para listas muito grandes, prefira a versao iterativa. Para entender melhor recursao e tratamento de erros, consulte nosso guia.


Modulo bisect: Busca Binaria Profissional

O modulo bisect da biblioteca padrao oferece busca binaria otimizada, implementada em C:

import bisect

# Lista ordenada
numeros = [2, 5, 8, 12, 16, 23, 38, 56, 72, 91]

# bisect_left: ponto de insercao a esquerda
pos = bisect.bisect_left(numeros, 23)
print(pos)  # 5 (indice onde 23 esta)

# Verificar se o elemento existe
def buscar(lista, alvo):
    pos = bisect.bisect_left(lista, alvo)
    if pos < len(lista) and lista[pos] == alvo:
        return pos
    return -1

print(buscar(numeros, 23))   # 5
print(buscar(numeros, 50))   # -1

bisect_left vs bisect_right

import bisect

# Lista com duplicatas
notas = [5.0, 6.0, 7.0, 7.0, 7.0, 8.0, 9.0]

# bisect_left: insere ANTES dos iguais
print(bisect.bisect_left(notas, 7.0))   # 2

# bisect_right: insere DEPOIS dos iguais
print(bisect.bisect_right(notas, 7.0))  # 5

# Util para encontrar o intervalo de elementos iguais
esquerda = bisect.bisect_left(notas, 7.0)
direita = bisect.bisect_right(notas, 7.0)
print(f"Notas 7.0 estao nos indices {esquerda} a {direita - 1}")
# "Notas 7.0 estao nos indices 2 a 4"

insort: Inserir Mantendo a Ordem

import bisect

# Manter lista ordenada durante insercoes
placar = [72, 85, 91, 95]

bisect.insort(placar, 88)
print(placar)  # [72, 85, 88, 91, 95]

bisect.insort(placar, 65)
print(placar)  # [65, 72, 85, 88, 91, 95]

insort() e equivalente a lista.insert(bisect.bisect_right(lista, x), x), mas otimizado.


Aplicacoes Praticas

Classificacao por Faixa

import bisect

def classificar_nota(nota):
    faixas = [6.0, 7.0, 8.0, 9.0]
    conceitos = ["F", "D", "C", "B", "A"]
    indice = bisect.bisect(faixas, nota)
    return conceitos[indice]

print(classificar_nota(5.5))   # "F"
print(classificar_nota(6.0))   # "D"
print(classificar_nota(7.5))   # "C"
print(classificar_nota(9.5))   # "A"

Buscar o Valor Mais Proximo

import bisect

def valor_mais_proximo(lista_ordenada, alvo):
    pos = bisect.bisect_left(lista_ordenada, alvo)

    if pos == 0:
        return lista_ordenada[0]
    if pos == len(lista_ordenada):
        return lista_ordenada[-1]

    antes = lista_ordenada[pos - 1]
    depois = lista_ordenada[pos]

    return antes if (alvo - antes) <= (depois - alvo) else depois

precos = [9.90, 19.90, 29.90, 49.90, 99.90]
print(valor_mais_proximo(precos, 35.00))  # 29.90
print(valor_mais_proximo(precos, 45.00))  # 49.90

Busca Binaria em Strings

import bisect

# Dicionario de palavras ordenado
palavras = ["abacaxi", "banana", "cereja", "damasco", "figo", "goiaba"]

def buscar_palavra(dicionario, palavra):
    pos = bisect.bisect_left(dicionario, palavra)
    if pos < len(dicionario) and dicionario[pos] == palavra:
        return f"'{palavra}' encontrada no indice {pos}"
    return f"'{palavra}' nao encontrada"

print(buscar_palavra(palavras, "cereja"))    # Encontrada
print(buscar_palavra(palavras, "manga"))     # Nao encontrada

Busca Binaria em Entrevistas Tecnicas

Busca binaria e um dos temas mais cobrados em entrevistas tecnicas Python. Problemas classicos incluem:

Encontrar o Primeiro/Ultimo Indice

import bisect

def primeiro_indice(lista, alvo):
    """Encontra o primeiro indice de um valor em lista com duplicatas."""
    pos = bisect.bisect_left(lista, alvo)
    if pos < len(lista) and lista[pos] == alvo:
        return pos
    return -1

def ultimo_indice(lista, alvo):
    """Encontra o ultimo indice de um valor em lista com duplicatas."""
    pos = bisect.bisect_right(lista, alvo) - 1
    if pos >= 0 and lista[pos] == alvo:
        return pos
    return -1

numeros = [1, 2, 2, 2, 3, 4, 5]
print(primeiro_indice(numeros, 2))  # 1
print(ultimo_indice(numeros, 2))    # 3

Raiz Quadrada Inteira

def raiz_quadrada_inteira(n):
    """Encontra o maior inteiro x onde x*x <= n."""
    esquerda, direita = 0, n

    while esquerda <= direita:
        meio = (esquerda + direita) // 2
        quadrado = meio * meio

        if quadrado == n:
            return meio
        elif quadrado < n:
            esquerda = meio + 1
        else:
            direita = meio - 1

    return direita  # Maior inteiro cujo quadrado <= n

print(raiz_quadrada_inteira(16))   # 4
print(raiz_quadrada_inteira(20))   # 4 (4^2=16 <= 20, 5^2=25 > 20)

Complexidade e Analise

AspectoBusca LinearBusca Binaria
ComplexidadeO(n)O(log n)
Pre-requisitoNenhumLista ordenada
Espaco extraO(1)O(1) iterativa, O(log n) recursiva
Melhor paraListas pequenas, nao ordenadasListas grandes, ordenadas
ImplementacaoSimplesModerada

Quando Nao Usar Busca Binaria

  • Dados nao ordenados: O custo de ordenar O(n log n) pode nao compensar
  • Poucas buscas: Se busca apenas uma vez, busca linear pode ser suficiente
  • Dados em dicionarios: Use dict para busca O(1) por chave
  • Dados dinamicos: Se insere/remove frequentemente, considere arvores balanceadas

Conclusao

Busca binaria e um algoritmo fundamental que todo desenvolvedor Python deve dominar. Na pratica, use o modulo bisect para codigo de producao e implemente manualmente para entrevistas e aprendizado.

Continue explorando algoritmos e estruturas de dados: listas, dicionarios, ordenacao e pilhas e filas.

Para mais desafios de algoritmos em Python, prepare-se com nosso guia de entrevistas Python e confira as vagas Python disponveis no mercado.

Algoritmos sao universais — veja como implementar em outras linguagens: Go, Rust e Kotlin.