O Padrão Ouro da Ordenação: O(N log N)

Published: (November 29, 2025 at 07:37 PM EST)
3 min read
Source: Dev.to

Contexto

Nos posts anteriores, conquistamos:

  • Busca Binária – complexidade O(log N)
  • Eficiência Linear – complexidade O(N)

Agora, vamos ao padrão‑ouro para ordenação: a complexidade O(N log N) (linearithmic).

Todo algoritmo de ordenação que precisa escalar para grandes volumes de dados (como Merge Sort ou Quick Sort) mira nessa complexidade, pois combina:

  • o poder de dividir o problema (log N)
  • a eficiência de processar os resultados de forma linear (N)

Como o Merge Sort atinge O(N log N)

O Merge Sort (Ordenação por Mesclagem) é um exemplo clássico de Divide and Conquer. Ele funciona em duas fases, que correspondem diretamente à sua complexidade O(N log N):

  1. Divisão recursiva

    • O algoritmo divide a lista em metades até que restem listas de um único elemento (caso base).
    • Ex.: com 1 000 000 de itens são necessárias apenas ≈ 20 divisões (log₂ 1 000 000 ≈ 20).
    • O log N representa a altura da árvore de recursão.
  2. Mesclagem

    • Em cada nível da recursão (há log N níveis) o algoritmo combina as listas ordenadas de volta em uma única lista maior e ordenada.
    • Para mesclar duas listas que, juntas, somam N elementos, são necessárias no máximo N comparações.
    • Essa operação é intrinsecamente O(N) (linear).

Como realizamos O(N) em cada um dos log N níveis, a complexidade total é O(N log N).

O(N) em Elixir: a função merge

A chave para um Merge Sort eficiente é garantir que a função de mesclagem seja rigorosamente O(N). Em Elixir, isso significa:

  • nunca usar o operador de concatenação lenta (++)
  • trabalhar apenas nas cabeças das listas

Código de mesclagem

## --- O CORAÇÃO O(N) DA MESCLAGEM ---

## Casos base para quando uma das listas se esgota:
defp merge([], list_b), do: list_b
defp merge(list_a, []), do: list_a

## Cláusula Recursiva Principal
defp merge([h_a | t_a] = list_a, [h_b | t_b] = list_b) do
  if h_a <= h_b do
    # h_a é menor: coloca na frente do resultado e continua a recursão
    # usando a cauda de A (t_a) e a lista B completa (list_b).
    [h_a | merge(t_a, list_b)]
  else
    # h_b é menor: coloca na frente do resultado e continua a recursão
    # usando a lista A completa (list_a) e a cauda de B (t_b).
    [h_b | merge(list_a, t_b)]
  end
end

Implementação completa do Merge Sort

defmodule MergeSort do
  @doc "Implementação do Merge Sort em Elixir (O(N log N))."
  def sort(list) do
    case list do
      [] -> []                     # Caso base
      [_] -> list                  # Caso base
      _ ->
        # 1. DIVISÃO
        {low, high} = split_list(list)

        # 2. RECURSÃO
        sorted_low  = sort(low)
        sorted_high = sort(high)

        # 3. MESCLAGEM
        merge(sorted_low, sorted_high)
    end
  end

  ## 🛠️ FUNÇÃO AUXILIAR DE DIVISÃO (Adicionada para corrigir o erro)
  # O(N) para encontrar o comprimento e dividir a lista ligada.
  defp split_list(list) do
    # Encontrar o ponto médio da lista
    len = length(list)
    split_point = trunc(len / 2)

    # Enum.split faz a divisão no ponto (O(N) por varrer a lista)
    Enum.split(list, split_point)
  end

  # Função de mesclagem (definida acima)
  defp merge([], list_b), do: list_b
  defp merge(list_a, []), do: list_a

  defp merge([h_a | t_a] = list_a, [h_b | t_b] = list_b) do
    if h_a <= h_b do
      [h_a | merge(t_a, list_b)]
    else
      [h_b | merge(list_a, t_b)]
    end
  end
end

Conclusão

O Merge Sort é o melhor que podemos fazer para ordenação genérica. Ele garante a performance O(N log N) em todos os casos (pior, médio e melhor), o que o torna incrivelmente estável e confiável.

Próximo post – Aplicação avançada do O(N): usaremos a técnica dos Dois Ponteiros para resolver o problema Squares of a Sorted Array, transformando a necessidade de uma ordenação O(N log N) em um único e elegante passo O(N). Também revelaremos o segredo do O(1) dos Mapas de Elixir (estrutura HAMT).

Back to Blog

Related posts

Read more »

Day 1276 : Career Climbing

Saturday Before heading to the station, I did some coding on my current side project. Made some pretty good progress and then it was time to head out. Made i...

Losing Confidence

Article URL: https://eclecticlight.co/2025/11/30/last-week-on-my-mac-losing-confidence/ Comments URL: https://news.ycombinator.com/item?id=46114599 Points: 88...