Pesquisa e ordenação em arrays
Pesquisa sequencial e binária, ordenação por comparação e o confronto quicksort contra mergesort.
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 .
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: no pior caso, 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 , 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 porque cada passo continua a descartar metade.
Ordenação por comparação
| Algoritmo | Pior caso | Caso médio | Espaço extra | Estável |
|---|---|---|---|---|
| Seleção | não | |||
| Inserção | sim | |||
| Mergesort | sim | |||
| Quicksort | 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 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 comparações no pior caso. A intuição é que elementos têm ordens possíveis e cada comparação só distingue dois resultados, por isso são precisas pelo menos 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 :
- Divide em e .
- A primeira metade divide em e , que ordenam para (1 comparação: contra ) e (1 comparação). A intercalação compara com (fica ), com (fica ), com (fica ) e despeja o : com 3 comparações.
- A segunda metade divide em e ; esta ordena para (1 comparação) e a intercalação com compara com e com : com 2 comparações.
- A intercalação final de com compara com , com , com , com , com e com , e despeja o : com 6 comparações.
Total: comparações. Repara no padrão: cada nível da divisão faz cerca de comparações e há níveis, daí o . O preço é o vetor auxiliar de tamanho 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 com pivô faz 6 comparações e produz , com o já na posição final. Resolve (pivô , 2 comparações, fica igual), (pivô , 1 comparação, troca para ), (pivô , 2 comparações, passa a ) e (1 comparação, troca para ). Total: 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 . 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 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: para 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.