Conteúdos da cadeira

Pesquisa e ordenação em arrays

Pesquisa sequencial e binária, ordenação por comparação e o confronto quicksort contra mergesort.

Markdown

Perguntar sobre esta página

ChatGPTClaudePerplexityGeminiCopiar e abrir

Envia o link e pede à IA para ler a página. No Gemini, cola a pergunta copiada.

Ver pergunta para copiar
Nesta página

Ordenar é o problema mais estudado da computação, porque aparece dentro de quase tudo: pesquisar depressa, remover duplicados, juntar conjuntos, preparar dados para outro algoritmo. Esta página fixa a pesquisa em vetores, apresenta as ordenações que tens de saber seguir à mão e explica por que nenhuma ordenação por comparação escapa a O(nlogn)O(n \log n).

Pesquisar: sequencial e binária

A pesquisa sequencial percorre o vetor do início ao fim até encontrar o valor ou esgotar as posições: O(n)O(n) no pior caso, O(1)O(1) de espaço, e funciona em qualquer vetor. A pesquisa binária exige o vetor ordenado e compara com o elemento do meio: se o alvo for menor, continua na metade esquerda; se for maior, na direita. Cada comparação corta os candidatos a metade, por isso custa O(logn)O(\log n), como contaste na página anterior.

Há variantes que deves reconhecer: encontrar a primeira ou a última ocorrência num vetor com repetidos (quando o meio é igual ao alvo, continua-se para o lado respetivo em vez de parar), e o limite de inserção (a posição onde o valor entraria para manter a ordem). Todas mantêm O(logn)O(\log n) porque cada passo continua a descartar metade.

Ordenação por comparação

AlgoritmoPior casoCaso médioEspaço extraEstável
SeleçãoO(n2)O(n^2)O(n2)O(n^2)O(1)O(1)não
InserçãoO(n2)O(n^2)O(n2)O(n^2)O(1)O(1)sim
MergesortO(nlogn)O(n \log n)O(nlogn)O(n \log n)O(n)O(n)sim
QuicksortO(n2)O(n^2)O(nlogn)O(n \log n)O(logn)O(\log n)não

A ordenação por seleção repete “escolhe o mínimo do que falta e põe-no na posição”: simples, sempre quadrática, boa quando trocar é caro e comparar é barato. A ordenação por inserção insere cada elemento na parte já ordenada: quadrática no geral, mas O(n)O(n) num vetor quase ordenado, por isso é a escolha para entradas pequenas. Estável significa que elementos iguais mantêm a ordem relativa original, o que interessa quando ordenas por uma chave e há desempates noutra.

O limite fundamental: qualquer algoritmo que só compare pares de elementos precisa de Ω(nlogn)\Omega(n \log n) comparações no pior caso. A intuição é que nn elementos têm n!n! ordens possíveis e cada comparação só distingue dois resultados, por isso são precisas pelo menos log2(n!)nlogn\log_2(n!) \approx n \log n comparações para isolar a ordem certa. O mergesort atinge este limite; o quicksort atinge-o em média.

Mergesort num vetor de 7 elementos

O mergesort divide ao meio, ordena cada metade e intercala (merge) as metades ordenadas. Segue o vetor [5,2,7,1,6,3,4][5, 2, 7, 1, 6, 3, 4]:

  • Divide em [5,2,7,1][5, 2, 7, 1] e [6,3,4][6, 3, 4].
  • A primeira metade divide em [5,2][5, 2] e [7,1][7, 1], que ordenam para [2,5][2, 5] (1 comparação: 55 contra 22) e [1,7][1, 7] (1 comparação). A intercalação compara 22 com 11 (fica 11), 22 com 77 (fica 22), 55 com 77 (fica 55) e despeja o 77: [1,2,5,7][1, 2, 5, 7] com 3 comparações.
  • A segunda metade divide em [6][6] e [3,4][3, 4]; esta ordena para [3,4][3, 4] (1 comparação) e a intercalação com [6][6] compara 66 com 33 e com 44: [3,4,6][3, 4, 6] com 2 comparações.
  • A intercalação final de [1,2,5,7][1, 2, 5, 7] com [3,4,6][3, 4, 6] compara 11 com 33, 22 com 33, 55 com 33, 55 com 44, 55 com 66 e 77 com 66, e despeja o 77: [1,2,3,4,5,6,7][1, 2, 3, 4, 5, 6, 7] com 6 comparações.

Total: 1+1+3+1+2+6=141 + 1 + 3 + 1 + 2 + 6 = 14 comparações. Repara no padrão: cada nível da divisão faz cerca de nn comparações e há logn\log n níveis, daí o O(nlogn)O(n \log n). O preço é o vetor auxiliar de tamanho nn em cada intercalação.

Quicksort no mesmo vetor

O quicksort escolhe um pivô, particiona (menores à esquerda, maiores à direita) e resolve cada lado. Com o esquema de Lomuto e pivô na última posição, a primeira partição de [5,2,7,1,6,3,4][5, 2, 7, 1, 6, 3, 4] com pivô 44 faz 6 comparações e produz [2,1,3,4,6,7,5][2, 1, 3, 4, 6, 7, 5], com o 44 já na posição final. Resolve [2,1,3][2, 1, 3] (pivô 33, 2 comparações, fica igual), [2,1][2, 1] (pivô 11, 1 comparação, troca para [1,2][1, 2]), [6,7,5][6, 7, 5] (pivô 55, 2 comparações, passa a [5,7,6][5, 7, 6]) e [7,6][7, 6] (1 comparação, troca para [6,7][6, 7]). Total: 6+2+1+2+1=126 + 2 + 1 + 2 + 1 = 12 comparações.

Neste vetor o quicksort fez menos comparações (12 contra 14) e não usou vetor auxiliar. Mas o seu pior caso é real: com o vetor já ordenado e pivô na ponta, cada partição só isola um elemento e o custo degrada para O(n2)O(n^2). A defesa é escolher bem o pivô (aleatório, ou mediana de três) e mudar para inserção nas partições pequenas. É por isso que a STL usa uma variante híbrida no sort, não o quicksort puro.

Ordenação linear

Sem comparar pares, o limite nlognn \log n não se aplica. A counting sort conta quantas vezes aparece cada valor (quando os valores estão num intervalo pequeno conhecido) e reescreve o vetor: O(n+k)O(n + k) para kk valores possíveis. A radix sort ordena dígito a dígito com uma ordenação estável auxiliar. O truque é sempre o mesmo: trocar comparações por informação sobre os valores. Quando os valores são arbitrários, volta-se à comparação.

Ver o ficheiro no GitHub

À tua maneira

Escolhe como preferes ler.

Aparência
Ajustar cores e largura
Cor de destaque do tema FEUP
Tipo de letra

Álgebra, lógica e uma ideia de cada vez.

As tuas escolhas ficam guardadas neste navegador.

Pesquisar

Escreve para pesquisar em todo o site.

para escolher · Enter para abrir · Esc para fechar

Atalhos de teclado

Clica numa tecla para a mudar. Esc cancela. Backspace desativa.

PesquisarCtrl / Cmd K

Os atalhos não interferem enquanto escreves. Tab e Enter funcionam sempre.