Programação II
Ordenação
(sort)
Bruno Feijó
Quick Sort
Algoritmo Quick Sort (recursivo)
O algoritmo de Quick Sort foi desenvolvido por Sir Charles Hoare (Tony Hoare), em 1960, aos 26 anos. Suponha que você sabe colocar um dos elementos x do vetor (por exemplo, o primeiro) numa posição tal que todos os elementos antes são menores ou iguais a x e todos os elementos depois dele são maiores (note que, nesta tarefa, não importa se alguns elementos trocam de posição):
n elementos
5
4 3 7 1 2 6 9 1 4 35
7 6 9x
x
≤ x >x ≤ 5 >5 2Vamos denominar o elemento x escolhido de pivô e chamar esta etapa da ordenação de PARTIÇÃO. Neste caso, se você souber ordenar o subvetor esquerdo e o subvetor direito, você terá o vetor inicial completamente ordenado! Isto nos leva a definir uma função recursiva quicksort na qual o caso-base é um vetor com 1 ou nenhum elemento (e, neste caso, nada é preciso fazer) e o caso geral é fazer a partição seguida da chamada da função para o subvetor esquerdo e da chamada da função para o subvetor direito:
quicksort do vetor
se n>1 então
PARTIÇÃO com pivô x
quicksort do subvetor à esquerda de x quicksort do subvetor à direita de x
No próximo slide estão sugeridos um processo simples e direto para a PARTIÇÃO e uma maneira de se referenciar aos subvetores à esquerda e à direita de x.
Algoritmo Quick Sort (recursivo)
25 48 37 12 57 86 33 92 a b a b troca e incr/decr 12 48 ab não troca nem in/decr
a b troca pivô 12 25 37 48 57 86 33 92 12 25 37 57 86 33 92
x
a b a b a b b...
av
a> x
v
b≤ x
se a < b, troca e incrementase b < a, troca pivô x com
v
bv
bx
v
aregião dos ≤ x região dos > x
posição correta de x subvetor subvetor 0 a b n - a
repete processo para cada subvetor
caminham até que decr b se vb> x incr a se va≤ x b b b
quicksort(n,v)
se n <= 1 então retorna
x = v
0a = 1 b = n-1
faça
enquanto a < n e v
a≤
x
a = a + 1
enquanto v
b> x
b = b - 1
se a < b então troca v
acom v
be a= a+1 e b= b-1
enquanto a ≤ b
troca pivô x com v
bquicksort(b, subvetor esquerdo)
quicksort(n-a, subvetor direito)
Para a PARTIÇÃO, podemos ir caminhando com os índices do vetor:
fica repetindo até que
Código Quick Sort
25 48 37 12 57 86 33 92 a b a b 12 48 a b a b 12 25 37 48 57 86 33 92 12 25 37 57 86 33 92 quicksort(n,v) se n <= 1 então retorna x = v0 a = 1 b = n-1 faça enquanto a < n e va≤x a = a + 1 enquanto vb> x b = b - 1se a < b então troca vacom vb e a= a+1 e b= b-1 enquanto a ≤ b
troca pivô x com vb
quicksort(b, subvetor esquerdo) quicksort(n-a, subvetor direito)
void quicksort(int n, int * v) { int x = v[0]; int temp; int a = 1; int b = n-1; if (n<=1) return; do {
while (a < n && v[a] <= x) a++; while (v[b] > x) b--; if (a < b) { temp = v[a]; v[a] = v[b]; v[b] = temp; a++; b--; } } while (a <= b); v[0] = v[b]; v[b] = x; quicksort(b,v); quicksort(n-a,&v[a]); }
Pa
rt
içã
o
Generalizando o Algoritmo Quick Sort
O desenvolvimento apresentado nos slides anteriores refere-se à ordenação em ordem CRESCENTE de um vetor de INTEIROS. Uma primeira generalização é perceber que a partição divide o vetor em
elementos que atendem o critério de ordenação à direita do pivô e elementos que NÃO atendem à esquerda. Por exemplo, a ilustração da partição para uma ordem DECRESCENTE seria:
5
4 3 7 1 2 6 9 7 9 65
2 3 4≥ 5 <5 1
O critério de ordenação pode ser definido numa função auxiliar de comparação que é usada em dois momentos no algoritmo de quick sort, sendo um momento a negação do outro (operador !):
static int cmpInt(int a, int b) {
return a < b; }
void quicksort(int n, int * v) { int x = v[0]; int temp; int a = 1; int b = n-1; if (n<=1) return; do {
while (a < n && !cmpInt(v[a],x)) a++; while (cmpInt(v[b],x)) b--; if (a < b) { temp = v[a]; v[a] = v[b]; v[b] = temp; a++; b--; } } while (a <= b); v[0] = v[b]; v[b] = x; quicksort(b,v); quicksort(n-a,&v[a]); }
Exercícios
struct dados { int idade; int peso; };typedef struct dados Dados;
[1] Escreva programa completo que ordena um vetor de ponteiros para
estrutura Dados através do Quick Sort (e usando função de comparação), de acordo
o seguinte critério: primeiro em ordem crescente da idade e depois em ordem
crescente do peso.
Sugestão para teste:
Dados tab[] = {{20,50},{10,30},{25,40},{18,65},{10,40},{18,60}}; Dados * v[] = {tab,tab+1,tab+2,tab+3,tab+4,tab+5};
Ponteiros para Funções
•
Em C é possível definir ponteiros para funções que podem ser colocados em
vetores, passados para funções e retornados por funções
•
No exemplo a seguir, a função opera(m, x, y, func) recebe um ponteiro de função
como um de seus argumentos (func) e retorna m
×
func(x,y). Devemos notar que o
nome da função mult é um ponteiro quando escrevemos opera(2,3,5,mult);
#include <stdio.h>
int mult(int x,int y);
int soma(int x, int y);
int opera(int m, int x, int y, int(*func)(int, int));
int main(void) { int a, b; a = opera(2,3,5,mult); b = opera(2,3,5,soma); printf("%d %d\n",a,b); return 0; }
int mult(int x,int y) {
return x*y; }
int soma(int x, int y) {
return x+y; }
int opera(int m,int x,int y,int(*func)(int, int)) {
return m*func(x,y); }
Saída:
30 16
Se argumentos são ponteiros, usamos const quando queremos garantir que a função func não modificará os valores que são apontados: int(*func)(const int *, const int *))
Quick Sort da stdlib do C
void qsort(void * v, int n, int tam, int (*cmp)(const void *, const void *)); v: vetor de ponteiros genéricos
n: número de elementos do vetor
tam: tamanho em bytes de cada elemento (use sizeof para especificar) cmp: ponteiro para função que compara elementos genéricos
int nome(const void * a, const void * b);
deve retornar <0 se a<b, >0 se a>b e 0 se a == b
const é para garantir que a função não modificará os valores dos elementos
static int compFloat(const void * a, const void * b) {
/* converte os ponteiros genericos */
float * aa = (float *)a; float * bb = (float *)b;
/* faz a comparacao com (*aa) e (*bb) retornando -1,0, ou 1 */ if (*aa > *bb) // atenção para o *
return 1; else if (*aa < *bb) return -1; else return 0; }
Exemplo Quick Sort da stdlib
#include <stdlib.h>
int main(void) {
...
Pessoa tab[] = {{"Diana Maria",22}, ...}; Pessoa * v[] = {tab,tab+1, ...};
...
QsortPessoa(n,tabPessoa); // ordenacao com Quick Sort
... }
int compPessoa(const void * a, const void * b) {
Pessoa ** aa = (Pessoa **)a; Pessoa ** bb = (Pessoa **)b; int cmp = strcmp((*aa)->nome,(*bb)->nome); if (cmp>0 || (cmp==0 && ((*aa)->idade>(*bb)->idade))) return 1; else if (cmp<0 || (cmp==0 && ((*aa)->idade<(*bb)->idade))) return -1; else return 0; }
void QsortPessoa(int n, Pessoa ** v) {
qsort(v,n,sizeof(Pessoa *),compPessoa); }
Bubble Sort – Ordem Crescente
•
Apenas de interesse didático e de referência
•
A idéia é ir comparando dois vizinhos e trocando o menor pelo maior até
que o maior de todos fica no final (como se o maior fosse uma “bolha”
que sobe até o topo)
0 1 1 2 j j+1
...
...
0 1 j j+1...
passo 1
passo 2
passo 3
...
1 2
...
Exemplo Bubble Sort – Passo 1 e Passo 2
25 48
37 12 57 86 33 92
25x48
25
48 37
12 57 86 33 92
48x37 troca
25 37
48 12
57 86 33 92
48x12 troca
25 37 12
48 57
86 33 92
48x57
25 37 12 48
57 86
33 92
57x86
25 37 12 48 57
86 33
92
86x33 troca
25 37 12 48 57 33
86 92
86x92
25 37 12 48 57 33 86
92
final do passo 1
o maior elemento, 92, já está na sua posição final
25 37
12 48 57 33 86
92
25x37
25
37 12
48 57 33 86
92
37x12 troca
25 12
37 48
57 33 86
92
37x48
25 12 37
48 57
33 86
92
48x57
25 12 37 48
57 33
86
92
57x33 troca
25 12 37 48 33
57 86
92
57x86
25 12 37 48 33 57
86 92
final do passo 2
o segundo maior elemento, 86, já está na sua posição final
n = 8 elementos
n – 1 c om p ar aç õe s ( i. e . 7 ) n – 2 c om p ar aç õe s ( i. e . 6 )Bubble Sort – Passo 3 e Passo 4
25 12
37 48 33 57
86 92
25x12 troca
12
25 37
48 33 57
86 92
25x37
12 25
37 48
33 57
86 92
37x48
12 25 37
48 33
57
86 92
48x33 troca
12 25 37 33
48 57
86 92
48x57
12 25 37 33 48
57 86 92
final passo 3
Idem para 57.
12 25 37 33 48 57 86 92
12x25
12 25 37 33 48 57 86 92
25x37
12 25 37 33 48 57 86 92
37x33 troca
12 25 33 37 48 57 86 92
37x48
12 25 33 37 48 57 86 92
final do passo 4
Idem para 48.
Não irá trocar mais.
Veja isto no próximo passo
n – 3 (= 5 ) n – 4 (= 4 )
Bubble Sort – Passos 5, 6 e 7
12 25 33 37 48 57 86 92
12x25
12 25 33 37 48 57 86 92
25x33
12 25 33 37 48 57 86 92
33x37
12 25 33 37 48 57 86 92
final do passo 5
Idem para 37.
12 25
33
37 48 57 86 92
12x25
12
25 33
37 48 57 86 92
25x33
12 25
33 37 48 57 86 92
final do passo 6
Idem para 33.
12 25
33 37 48 57 86 92
12x25
12
25 33 37 48 57 86 92
final do passo 7
Idem para 25 e, conseqüentemente, 12.
12 25 33 37 48 57 86 92
final da ordenação
Passo 5 sem troca!
Os dois próximos
passos são
desperdícios!
n – 5 (= 3 ) n – 6 (= 2 ) n – 7 (= 1 )Algoritmo de Bubble Sort – Solução Conceitual
bolhaInt(vetor v de inteiros, n) i = n-1
para cada i, enquanto i>0
haTroca= 0 // p/rastrear trocas j = 0
para cada j, enquanto j<i
se compInt(vj,vj+1) é VERDADE troca vj e vj+1
haTroca= 1; // marca troca incrementa j de 1
if haTroca é zero retorna
decrementa i de 1
DICAS PARA A IMPLEMENTAÇÃO: - Use for para os loops.
- Para trocar vj e vj+1use uma variável auxiliar. - A função de comparação deve retornar VERDADE (valor diferente de zero) ou FALSO (zero).
- Os argumentos desta função são do mesmo tipo do vetor.
- Geralmente definimos esta função como sendo static. Função static é invisível fora do arquivo no qual é declarada.
- Este algoritmo é geral. Só muda o que está em
vermelho e itálico.
O critério de ordenação é definido dentro
desta função comp
Int
que compara dois
elementos do vetor (no caso, 2 inteiros).
Ordem Crescente:
static int compInt(int a, int b) {
return a > b; }
Ordem Decrescente:
static int compInt(int a, int b) {
return a < b; }
Código bolhaInt – Ordem Crescente
void bolhaInt(int * v, int n) { int i,j,haTroca; int temp; for (i=n-1;i>0;i--) { haTroca= 0; for (j=0;j<i;j++) { if (compInt(v[j],v[j+1])) { temp = v[j]; v[j] = v[j+1]; v[j+1] = temp; haTroca= 1; } } if (haTroca==0) return; } } bolhaInt(vetor v de inteiros, n)
i = n-1
para cada i, enquanto i>0 haTroca= 0
j = 0
para cada j, enquanto j<i
se compInt(vj,vj+1) é VERDADE troca vj e vj+1
haTroca= 1; // marca troca incrementa j de 1
if haTroca é zero retorna
decrementa i de 1
static int compInt(int a, int b) {
return a > b; }
Para outros tipos, só muda o que está em vermelho e itálico
troca
Depois faça para vetor de strings (bolhaStr), ordem crescente. Resposta no próximo slide!
Código bolhaStr – Ordem Crescente
void bolhaStr(char ** v, int n) { int i,j,haTroca; char * temp; for (i=n-1;i>0;i--) { haTroca= 0; for (j=0;j<i;j++) { if (compStr(v[j],v[j+1])) { temp = v[j]; v[j] = v[j+1]; v[j+1] = temp; haTroca= 1; } } if (haTroca==0) return; } } int main(void) { char * v[] = {"daniel","ana",...,}; ... bolhaStr(tab, N); ...
static int compStr(char * a, char * b) {
return (strcmp(a,b) > 0); }
troca
strcmp(x,y) é uma função da biblioteca de strings que retorna o seguinte:
< 0 se o primeiro caractere que não casa tem um valor mais baixo em x do que em y
0 se os conteúdos dos dois strings são iguais >0 se o primeiro caractere que não casa tem um
valor mais alto em x do que em y
Por ex.: strcmp("daniel","ana") retorna > 0
strcmp("Ana","ana") retorna < 0 (porque 'A' é menor que 'a' na tabela ASCII
Exercícios
typedef struct pessoa Pessoa; struct pessoa
{
char * nome; int idade; };
[1] Escreva programa completo, em módulos, que ordena um vetor de ponteiros para
estrutura Pessoa:
usando o seguinte critério: ordem crescente de nome e ordem crescente de idade
(note que há 3 Diana Maria de idades diferentes).
Obs1: evite ninhos de if e use expressões booleanas (com ||, && e !). Obs2: para montar o vetor, declare e inicialize vetores:
Pessoa tab[] = {{"Diana Maria",22}, ...}; Pessoa * v[] = {tab,tab+1, ...};
Obs3: faça uma função auxiliar imprimeVetPessoa que imprime o vetor
Diana Maria 22 Beatrice Dante 30 Ada Eva 30 Diana Maria 26 Beatrice Dante 29 Helena Troia 25 Diana Maria 20 Beatrice Dante 25
Código bolhaPessoa
void bolhaPessoa(Pessoa ** v, int n) { int i,j,haTroca; Pessoa * temp; for (i=n-1;i>0;i--) { haTroca= 0; for (j=0;j<i;j++) { if (compPessoa(v[j],v[j+1])) { temp = v[j]; v[j] = v[j+1]; v[j+1] = temp; haTroca= 1; } } if (haTroca==0) return; } } struct pessoa { char * nome; int idade; };
typedef struct pessoa Pessoa;
static int compPessoa(Pessoa * a, Pessoa * b) {
int cmp = strcmp(a->nome,b->nome);
return (cmp > 0 || (cmp==0 && (a->idade)>(b->idade))); } int main(void) { ... bolhaPessoa(v, N); ... trocaC
Algoritmo Genérico
void bolhaGen(void * v, int n, int tam, int(*comp)(const void *, const void *)) { int i,j,haTroca; void * p1; void * p2; for (i=n-1;i>0;i--) { haTroca= 0; for (j=0;j<i;j++) { p1 = acessa(v,j,tam); p2 = acessa(v,j+1,tam); if (comp(p1,p2)) troca(p1,p2,tam); haTroca= 1; } if (haTroca==0) return; } }
static void * acessa(void * v,int i,int tam) {
char * t = (char *)v; // char = 1 byte
t += tam*i;
return (void *)t; }
static void troca(void * a, void * b, int tam) {
char temp;
char * v1 = (char *)a; // troca byte a byte
char * v2 = (char *)b;
int i;
for (i=0; i<tam; i++) { temp = v1[i]; v1[i] = v2[i]; v2[i] = temp; } }
static int compPessoaGen(const void * a, const void * b) {
Pessoa ** aa = (Pessoa **)a; Pessoa ** bb = (Pessoa **)b;
int cmp = strcmp((*aa)->nome,(*bb)->nome);
return (cmp>0 || (cmp==0 && (*aa)->idade > (*bb)->idade)); }
void ordenaPessoa(int n, Pessoa ** v) {
bolhaGen(v,n,sizeof(Pessoa *),compPessoa); }
Selection Sort
Conceito do Selection Sort – Ordem Crescente
- Supomos que o maior elemento (max) é o que está na posição 0
- A partir da posição 1, procuramos se há alguém maior (max) do que o valor na posição 0
- trocamos este máximo pelo último
- Deslocamos o fim do vetor para 1 (uma) posição à esquerda
- Repetimos o processo
Note que o processo vai dividindo o vetor em uma parte ordenada e outra não
ordenada. fim fim fim fim fim Um processo equivalente
é trabalhar com o mínimo e trocar com o primeiro. Neste caso, o vetor ordenado vai se
Selection Sort
void selectionInt(int * v, int n) {
int fim, iMax, i;
int temp;
for (fim = n-1; fim > 0; fim--) {
iMax= 0; /* indice do maior*/ for (i=1;i<=fim;i++) if ( v[i]> v[iMax] ) iMax = i; temp = v[fim]; v[fim] = v[iMax]; v[iMax] = temp; } troca
critério if ( compInt(v[i], v[iMax]) )
static int compInt(int a, int b) {
return a > b; }
Ou usando uma função
para um critério genérico
Implemente a versão que trabalha com o mínimo!
Complexidade
Complexidade de Tempo
•
O tempo gasto por um algoritmo é função do tamanho n da entrada de dados e
depende do número de operações que cada passo do algoritmo executa.
•
T(n) indica a dimensão este tempo de uma forma geral (e independente de hardware)
•
No caso do algoritmo Bubble, numa análise aproximada, o passo 1 faz n-1
comparações, o passo 2 faz n-2 comparações, ... . De maneira aproximada, temos:
•
Isto é igual à soma de uma série aritmética de m termos, onde m = n-1:
•
Para grandes valores de n (n
→ ∞), esta função é limitada pela função
bn
2, onde b é
uma constante, i.e.:
•
Como regra geral, o termo de mais alta ordem de uma função domina sua taxa de
crescimento (i.e., na prática, suprimimos constantes multiplicativas e termos de
baixa ordem para descrever o comportamento limite de uma função)
•
Dizemos, então, que o algoritmo Bubble tem uma complexidade de tempo quadrática
e usamos a notação do Big O para indicar este limite superior:
O(n
2)
1
2
)
2
(
)
1
(
)
(
n
=
n
−
+
n
−
+
+
+
T
(n-1) + (n-2) + ... + 2 + 1 Série Aritmética Sm = m(a1 + am)/2
am a1 m = n-1 Sm = n(n-1)/2
n
n
n
n
n
T
2
1
2
1
2
/
)
1
(
)
(
=
−
=
2−
2 22
1
2
1
)
(
n
n
n
bn
T
=
−
≤
Complexidades Comuns (notação Big O)
Notação Big O
O(1)
Tempo constante
O(log n)
Tempo logarítmico
O(n)
Tempo linear
O(n log n)
Tempo loglinear (ou quaselinear)
O(n
2)
Tempo quadrático
Limite
n
2n
n
n
T
2
1
2
1
)
(
=
2−
Quase linearn
Diferença entre n e log n
36 seg
100 anos
94 608 000 000
30
1 ano
946 080 000
21
1 mês
2 592 000
16
1 dia
86 400
12
1 h
3 600
9
10 min
600
6
1 min
60
3 seg
10 seg
10
O(log n)
O(n)
tamanho
Outras Considerações sobre Complexidade
•
Na análise de complexidade, procuramos o “Pior Caso”, o “Melhor Caso” e o
“Caso Médio”
– Bubble Sort tem o “Melhor Caso” quando a lista já está ordenada. Neste caso, a complexidade de tempo é
O(n)
– O “Caso Médio” para Bublle Sort também é
O(n
2)
•
Entre algoritmos de mesma complexidade, há diferenças em eficiência
– Por exemplo, Selection Sort é similar ao Bubble Sort e ambos tem
O(n
2)
, isto é: ele faz omesmo número de comparações que o Bubble. Entretanto, Selection Sort tem um menor número de comparações e tende a ser aproximadamente 2 vezes mais eficiente. Eficiência não é a mesma coisa que complexidade!
•
Em geral
– uma única operação (ou comando) tem um tempo de execução de
O
(1) – Um loop (laço) que é repetido n vezes temO(n)
– Dois laços aninhados (nested loops) indo de 1 a
n
temO(n
2)
•
Se um algoritmo tem vários passos de complexidades diferentes, a complexidade
do algoritmo como um todo é dado pelo máximo.
Complexidade do Quick Sort – Pior Caso
Esta etapa (que caminha pelo vetor, compara e troca valores) consome um tempo cn (*). As outras duas etapas são as chamadas recursivas. Temos, então:
(*)
o maior valor de cseria para um código que percorresse uma vez o vetor, guardando os elementos menores do que x (e o próprio x) em um vetor temporário, percorresse novamente o vetor, guardando os elementos maiores do que x, efinalmente copiasse o vetor temporário para o vetor original. Neste caso, o tempo seria 4n(i.e.c= 4).
A primeira etapa do algortimo de sort é colocar o pivô
x
na posição que divide o vetor entre os elementos menores quex
e os maiores quex
:x
k
n-k
cn
k
n
T
k
T
n
T
(
)
=
(
)
+
(
−
)
+
PIOR CASO: pivôx
é o menor, em cada passo. Neste caso, k =1 e n-k = n-1 passo 1:T
(
n
)
=
T
(
1
)
+
T
(
n
−
1
)
+
cn
passo 2:
T
(
n
)
=
T
(
1
)
+
[
T
(
1
)
+
T
(
n
−
2
)
+
cn
]
+
cn
=
T
(
n
−
2
)
+
2
T
(
1
)
+
c
(
n
−
1
+
n
)
passo 3:
T
(
n
)
=
[
T
(
1
)
+
T
(
n
−
3
)
+
c
(
n
−
2
)]
+
2
T
(
1
)
+
c
(
n
−
1
+
n
)
=
T
(
n
−
3
)
+
3
T
(
1
)
+
c
(
n
−
2
+
n
−
1
+
n
)
passoi
:T
(
n
)
=
T
(
n
−
i
)
+
iT
(
1
)
+
c
(
n
−
i
+
1
+
+
n
−
1
+
n
)
...
e considerando que vamos até
n
−
i
=1
, i.e.i
= n
−
1
, temos:T
(
n
)
=
nT
(
1
)
+
c
(
n
−
1
)(
n
+
2
)
A soma da série aritmética de
i
termosn
−
i+1,...,n
−
1,n
é:S
i=
i
(
2
n
+
1
−
i
)
/
2
A complexidade é, portanto:T
(
n
)
=
nT
(
1
)
+
c
(
n
−
1
)(
n
+
2
)
≤
dn
2→
O
( )
n
2 O mesmo vale para pivôx
sendo o maior.Complexidade do Quick Sort – Melhor Caso
MELHOR CASO: pivô
x
divide vetor em duas partes iguais, em cada passo. Neste caso, k =n/2 e n-k = n/2 passo 1:T
(
n
)
=
T
(
n
/
2
)
+
T
(
n
/
2
)
+
cn
=
2
T
(
n
/
2
)
+
cn
passo 2:
T
(
n
)
=
2
[
2
T
(
n
/
4
)
+
cn
/
2
]
+
cn
=
2
2T
(
n
/
2
2)
+
2
cn
passo 3:T
(
n
)
=
2
2[
2
T
(
n
/
2
3)
+
cn
/
2
2]
+
2
cn
=
2
3T
(
n
/
2
3)
+
3
cn
passo
i
:T
(
n
)
=
2
iT
(
n
/
2
i)
+
icn
...
considerando que vamos até
n/2
i= 1
, i.e.n
= 2
i , ou seja,i
= log n
, temos:Podemos também provar que no CASO MÉDIO (para todas as possíveis configurações de pivô), quick sort tem uma complexidade de tempo de O(n log n).
(
n
n
)
O
n
dn
n
cn
nT
n
T
(
)
=
(
1
)
+
log
≤
log
→
log
Melhoras no algoritmo podem ser feitas no sentido de reduzir a chance de ocorrer o pior caso. Uma idéia é pegar o pivô aleatóriamente cada vez. Outra idéia é encontrar a mediana do vetor
a ser ordenado cada vez, e usar a mediana como pivô (isto tem um custo extra alto de complexidade constante, mas que pode compensar ). Veja também o método baseado em 3 medianas.
Selection Sort pode ser mais vantajoso para listas pequenas (≤ 30) ou quase ordenadas.
Ironicamente, vetores já ordenados (ou quase ordenados) e com o pivô sendo o primeiro (ou o último) elemento representam situações tipo “pior caso”.