Sie sind auf Seite 1von 27

Ordenação de vectores

2007/08
A.E.D.
F.S.B.

 As técnicas usadas anteriormente usam todo o


vector e vão percorrendo todo o vector fazendo
comparações com elementos próximos
 Os algoritmos seguintes tomam apenas parte do
vector e fazem comparações entre elementos
distantes
 Foi provado que comparar elementos mais afastados
leva a melhores resultados
 Alguns, os mais rápidos, usam recursividade

Ordenação de vectores : ShellSort


2007/08
A.E.D.
F.S.B.

 Algoritmo de ShellSort
 Inventado por Donald Shell
 Neste caso percorre-se o vector ordenando apenas
elementos que se encontram afastados
 Para ordenar estes usa-se o algoritmo de inserção
 À distância entre elementos chama-se incremento
 Depois destes estarem ordenados ordenam-se os
mais próximos até se ordenarem os elementos
adjacentes
 Ou seja, vai-se diminuindo o incremento até este ser 1
 Como a distância entre elementos se aproxima de 1
este algoritmo também se costuma chamar
 Ordenação por incrementos decrescentes
Ordenação de vectores : ShellSort
2007/08
A.E.D.
F.S.B.

 Algoritmo de ordenação ShellSort, assumindo:


 vect é o vector a ordenar
 dim é a dimensão do vector
 O índice do primeiro elemento é 0 (zero)

PARA h = IncrementoInicial ATÉ 1 FAZER


PARA i = h ATÉ dim -1 FAZER
inserir x na posição correcta (k) entre
vect[0] e vect[i] com intervalos de h
FIM

 Só fica a faltar definir como se calcula o 1º incremento

Ordenação de vectores : ShellSort


2007/08
A.E.D.
F.S.B.

 Quais são os incrementos e como se calculam?


 A escolha dos incrementos deve ser feita com
cuidado pois incrementos diferentes podem levar
a soluções ineficientes
 Na solução original o incremento inicial era metade do
tamanho do vector
 Os seguintes seriam metade do anterior
 Foram depois sugeridas várias sequências de
incrementos que melhoravam substancialmente os
resultados obtidos com a original
Ordenação de vectores : ShellSort
2007/08
A.E.D.
F.S.B.

 Exemplificação do algoritmo com incrementos


originais
1ª iteração 2ª iteração 3ª iteração
h=4 h=2 h=1
9 9 2 2 2 2 2
3 3 3 3 3 3 3
5 5 5 5 5 5 5
11 11 11 11 11 11 6
2 2 8 8 8 8 7
7 7 7 7 7 7 8
12 12 12 12 9 12 9
6 6 6 6 6 6 11
8 8 9 9 12 9 12

Ordenação de vectores : ShellSort


2007/08
A.E.D.
F.S.B.

 Em que é que este algoritmo é melhor que o de


inserção directa?
 Afinal o algoritmo de inserção directa não é usado
para ordenar as subsquências?
 Com uma correcta escolha de índices este
algoritmo faz muito menos trocas
 E as trocas são o que mais influência o desempenho
 Quando se chega ao incremento 1 quase todos os
elementos estão no lugar
Ordenação de vectores : ShellSort
2007/08
A.E.D.
F.S.B.

 O algoritmo ShellSort pode ser implementado


pelo seguinte método, usando os índices
originais:

void ordenaShellOriginal( int v[] ) {

for( int h = v.length / 2; h >= 1; h = h/2 ) {


for( int i = h; i < v.length; i+= h ) {
int x = v[ i ];
int j = i;
while( j > 0 && v[ j-h ] > x ){
v[ j ] = v[ j-h ];
j -= h;
}
v[ j ] = x;
}
}

Ordenação de vectores : ShellSort


2007/08
A.E.D.
F.S.B.

 Outra sequência que se pode usar é uma em


que:
 hi = 3 * hi-1 + 1
 (1, 4, 13, 40, …)
 Para esta sequência tem-se de calcular o primeiro
incremento
 A melhor forma é calcular o incremento i com base no
anterior
 Começa-se em 1 e vai-se aplicando a fórmula até se

atingir o tamanho do vector


 Outra hipótese era aplicar logaritmos para determinar logo o
incremento inicial
 Não o vamos fazer ☺

 Esta é, até agora, a sequência de incrementos que dá


melhores resultados
Ordenação de vectores : ShellSort
2007/08
A.E.D.
F.S.B.

 O algoritmo ShellSort pode ser implementado


pelo seguinte método, usando a sequência
anterior:
void ordenaShellMelhor( int v[] ) {
int h;

// primeiro calcular o maior incremento (h) possível


for( h = 1; h < v.length; h = 3*h + 1);

do{
h /= 3; // actualizar o h para esta iteração
for( int i = h; i < v.length; i+= h ) {
int x = v[ i ];
int j = i;
while( j > 0 && v[ j-h ] > x ){
v[ j ] = v[ j-h ];
j -= h;
}
v[ j ] = x;
}
} while( h > 1 );
}

2007/08
A.E.D.
F.S.B. Ordenação de vectores : MergeSort
 Algoritmo de MergeSort
 Algoritmo recursivo
 Divide o vector a meio, formando dois vectores
 ordena-os separadamente
 reagrupa-os num novo vector
 Para ordenar os vectores resultantes aplica o mesmo
raciocínio
 Obriga a criar um novo vector por causa do
reagrupamento
2007/08
A.E.D.
F.S.B. Ordenação de vectores : MergeSort
 Exemplificação do algoritmo
 Divisão em sub-vectores

1ª chamada 2ª chamada 3ª chamada 4ª chamada


esq = 0 9
9 9 esq = 0 9 9 esq = 0 9 9 centro = 0
9 9 esq = 0 3 3 3 3 centro = 1 3 3 dir = 1
3 3 3
5 5 centro = 2 5 5 dir = 2
5 5 11 11 5
11 11 2 2 dir = 4 11
2 2 centro = 4 5ª chamada
2
7 7 esq = 0
9 dir = 0
12 12 7
6 6 12
8 8 dir = 8
Quando esq = dir,
6
8
termina a parte recursiva,
falta recuar nas chamadas

2007/08
A.E.D.
F.S.B. Ordenação de vectores : MergeSort
 Neste ponto coloca-se outro problema:
 Como se juntam dois vectores, já ordenados de modo
a ficarem um só vector?
 O algoritmo é simples:
 Verifica-se qual dos dois vectores tem o menor
número na posição inicial
 Coloca-se esse elemento na primeira posição de um
novo vector
 Passa-se ao elemento seguinte no vector de onde se
retirou o elemento
 No vector cujo elemento não foi retirado mantém-se na
mesma posição
 Repete-se o algoritmo para os restantes elementos
dos vectores, actualizando sempre o vector que foi
alterado
2007/08
A.E.D.
F.S.B. Ordenação de vectores : MergeSort
 Exemplificação do algoritmo
 Caso de junção de vectores

1ª iteração 2ª iteração 3ª iteração 4ª iteração 5ª iteração


1 i1 = 0 1 1 i=0 1 1 1 1 1 1 1 1
3 3 i1 = 1 3 2 i = 1 i1 = 1 3 2 3 2 3 2
4 4 4 4 3 i = 2 i1 = 2 4 3 4 3
6 6 6 6 6 4 i = 3 i1 = 3 6 4
9 9 9 9 9 9 5 i=4
10 10 10 10 10 10

2 i2 = 0 2 i2 = 0 2 2 2 2
5 5 5 i2 = 1 5 i2 = 1 5 i2 = 1 5
7 7 7 7 7 7
8 8 8 8 8 8

2007/08
A.E.D.
F.S.B. Ordenação de vectores : MergeSort
 Exemplificação do algoritmo
 Caso de junção de vectores

5ª iteração 6ª iteração 7ª iteração 8ª iteração 9ª e 10ª iterações


1 1 1 1 1 1 1 1 1 1 1
3 3 2 3 2 3 2 3 2 3 2
4 4 3 4 3 4 3 4 3 4 3
6 i1 = 3 6 4 i1 = 3 6 4 6 4 6 4 6 4
9 9 5 i=4 9 5 i1 = 4 9 5 i1 = 4 9 5 i1 = 4 9 5
10 10 10 6 i=5 10 6 10 6 10 6
7 i=6 7 7
2 2 2 2 2 8 i=7 2 8
5 i2 = 1 5 5 5 5 5 9 i=8
7 7 i2 = 2 7 i2 = 2 7 7 7 10 i = 9
8 8 8 8 i2 = 3 8 8
i2 = 4
Como o 2º vector já acabou não se compara mais,
é só copiar os elementos do outro vector
2007/08
A.E.D.
F.S.B. Ordenação de vectores : MergeSort
 O algoritmo para fundir os dois vectores vai ser o
apresentado
 Vai ser alterado porque os dois vectores
originais são o mesmo vector, mas partido em
diferentes partes
 O que vai variar são os índices onde se começa a
copiar
 No exemplo anterior basta por i2 a começar em 6
para que os dois vectores sejam afinal o mesmo

2007/08
A.E.D.
F.S.B. Ordenação de vectores : MergeSort
 Exemplificação do algoritmo
 Reagrupar os subvectores

1ª chamada 2ª chamada 3ª chamada 4ª chamada


esq = 0 9
9 9 esq = 0 9 9 esq = 0 9 9 centro = 0
9 9 esq = 0 3 3 3 3 centro = 1 3 3 dir = 1
3 3 3
5 5 centro = 2 5 5 dir = 2
5 5 11 11 5
11 11 2 2 dir = 4 11
2 2 centro = 4 5ª chamada
2
7 7 esq = 0
9 dir = 0
12 12 7
6 6 12
8 8 dir = 8
Quando esq = dir,
6
8
termina a parte recursiva,
falta recuar nas chamadas
2007/08
A.E.D.
F.S.B. Ordenação de vectores : MergeSort
 Exemplificação do algoritmo
 Reagrupar os subvectores

1ª chamada 2ª chamada 3ª chamada 4ª chamada


esq = 0 9 3
9 9 esq = 0 9 9 esq = 0 9 9 centro = 0
9 9 esq = 0 3 3 3 3 centro = 1 3 3 dir = 1 9
3 3 3
5 5 centro = 2 5 5 dir = 2
5 5 11 11 5
11 11 2 2 dir = 4 novo vector
11
2 2 centro = 4
7 7
2 Para a recursividade funcionar deve-se
12 12 7 copiar o novo vector para o antigo
6 6 12
8 8 dir = 8 6
8

2007/08
A.E.D.
F.S.B. Ordenação de vectores : MergeSort
 Exemplificação do algoritmo
 Reagrupar os subvectores

1ª chamada 2ª chamada 3ª chamada 4ª chamada


esq = 0 9 3
9 9 esq = 0 9 9 esq = 0 3 3 centro = 0
9 9 esq = 0 3 3 3 3 centro = 1 9 9 dir = 1 9
3 3 3
5 5 centro = 2 5 5 dir = 2
5 5 11 11 5
11 11 2 2 dir = 4 novo vector
11
2 2 centro = 4 é copiado
2
7 7
12 12 7
6 6 12
8 8 dir = 8 6
8
2007/08
A.E.D.
F.S.B. Ordenação de vectores : MergeSort
 Exemplificação do algoritmo
 Reagrupar os subvectores

1ª chamada 2ª chamada 3ª chamada


9 9 esq = 0 9 9 esq = 0 3 3
9 9 esq = 0 3 3 3 3 centro = 1 9 5
3 3 5 5 centro = 2 5 5 dir = 2 9
5 5 11 11 5
11 11 2 2 dir = 4 11
2 2 centro = 4
2
7 7
12 12 7
6 6 12
8 8 dir = 8 6
8

2007/08
A.E.D.
F.S.B. Ordenação de vectores : MergeSort
 Exemplificação do algoritmo
 Reagrupar os subvectores

1ª chamada 2ª chamada 3ª chamada


9 9 esq = 0 3 3 esq = 0 3 3
9 9 esq = 0 3 3 5 5 centro = 1 9 5
3 3 5 5 centro = 2 9 9 dir = 2 9
5 5 11 11 5
11 11 2 2 dir = 4 2
2 2 centro = 4
11
7 7
12 12 7
6 6 12 Este vector também foi alterado
8 8 dir = 8 6
8
2007/08
A.E.D.
F.S.B. Ordenação de vectores : MergeSort
 Exemplificação do algoritmo
 Reagrupar os subvectores

1ª chamada 2ª chamada
9 9 esq = 0 3 2
9 9 esq = 0 3 3 5 3
3 3 5 5 centro = 2 9 5
5 5 11 11 9
11 11 2 2 dir = 4 11
2
2 2 centro = 4
11
7 7
12 12 7
6 6 12
8 8 dir = 8 6
8

2007/08
A.E.D.
F.S.B. Ordenação de vectores : MergeSort
 Exemplificação do algoritmo
 Reagrupar os subvectores

1ª chamada 2ª chamada
2 2 esq = 0 3 2
9 9 esq = 0 3 3 5 3
3 3 5 5 centro = 2 9 5
5 5 9 9 9
11 11 11 11 dir = 4 11
2
2 2 centro = 4
11
7 7
12 12 6
6 6 7
8 8 dir = 8 8
12
Este vector também foi alterado
2007/08
A.E.D.
F.S.B. Ordenação de vectores : MergeSort
 Exemplificação do algoritmo
 Reagrupar os subvectores

1ª chamada
2
9 9 esq = 0 3 2
3 3 5 3
5 5 9 5
11 11 11 6
2 2 centro = 4 7
7 7 8
12 12 6 9
6 6 7 11
8 8 dir = 8 8 12
12

2007/08
A.E.D.
F.S.B. Ordenação de vectores : MergeSort
 Exemplificação do algoritmo
 Reagrupar os subvectores

1ª chamada
2
2 2 esq = 0 3 2
3 3 5 3
5 5 9 5
6 6 11 6
7 7 centro = 4 7
8 8 8
9 9 6 9
11 11 7 11
12 12 dir = 8 8 12
12
2007/08
A.E.D.
F.S.B. Ordenação de vectores : MergeSort
 O algoritmo MergeSort para ser implementado
exigue vários métodos:
 O método inicial cria o vector novo e começa a
chamada recursiva
 O método que é recursivo e vai partindo os vectores a
meio
 O método que faz o reagrupamento

2007/08
A.E.D.
F.S.B. Ordenação de vectores : MergeSort
 O método inicial cria o vector novo e começa a
chamada recursiva, pode ser assim
implementado

void ordenaMergeSort( int v[] ) {

// criar o vector auxiliar para o reagrupamento


int vAux[] = new int[ v.length ];

// dividir em dois e começar a recursão


// indicando onde começa e acaba o vector a ser ordenado
mergeSortRec( v, vAux, 0, v.length-1);
}
2007/08
A.E.D.
F.S.B. Ordenação de vectores : MergeSort
 O método que é recursivo e vai partindo os
vectores em 2, pode ser assim implementado

void mergeSortRec( int v[], int vAux[], int esq, int dir ) {

if( esq >= dir ) // se só tem um elemento não faz nada


return;

// senão divide em duas partes e ordena essas partes


int centro = (esq + dir) / 2;
mergeSortRec( v, vAux, esq, centro ); // 1ª metade
mergeSortRec( v, vAux, centro+1, dir ); // 2ª metade

// as partes já estão ordenadas, reagrupá-las


reagrupar( v, vAux, esq, centro+1, dir);
}

2007/08
A.E.D.
F.S.B. Ordenação de vectores : MergeSort
 O método que faz o reagrupamento, pode ser
assim implementado
void reagrupar( int v[], int vAux[], int i1, int i2, int fim2 ) {
// a primeira parte do vector vai de i1 a i2-1
int fim1 = i2-1;
// e a segunda de i2 a fim

// guardar o início pois vai ser preciso para a cópia final


int inicio = i1;

// o índice do vector auxiliar vai começar em i1


int iAux = i1;

// enquanto houver elementos nos dois vectores


// copiar o menor para vAux e incrementar o i respectivo
while( i1 <= fim1 && i2 <= fim2 ){
if( v[ i1 ] < v[ i2 ] ) {
vAux[iAux] = v[ i1 ];
i1++;
}
else {
vAux[iAux] = v[ i2 ];
i2++;
}
iAux++;
}

// … continua no seguinte
2007/08
A.E.D.
F.S.B. Ordenação de vectores : MergeSort
 O método que faz o reagrupamento, pode ser
assim implementado

// … continuação do anterior

for( ; i1 <= fim1; i1++, iAux++ ) // o 2º vector acabou


vAux[ iAux ] = v[ i1 ];
for( ; i2 <= fim2; i2++, iAux++ ) // o 1º vector acabou
vAux[ iAux ] = v[ i2 ];

// copiar novamente para origem


for( int i = inicio; i <= fim2; i++ )
v[i] = vAux[i];
}

2007/08
A.E.D.
F.S.B. Ordenação de vectores : QuickSort
 Algoritmo de QuickSort
 Algoritmo recursivo
 Mais rápido algoritmo de ordenação existente
 Primeiro é escolhido um valor (pivot)
 Divide o vector em duas partes
 A primeira parte com elementos menores que o pivot
 A segunda parte com elementos maiores que o pivot
 O pivot é colocado no meio das duas partes
 Para ordenar as partes dai resultantes aplica-se o
mesmo raciocínio
2007/08
A.E.D.
F.S.B. Ordenação de vectores : QuickSort
 Exemplificação do algoritmo
 Usando um pivot completamente arbitrário!

1ª chamada 2ª chamada 3ª chamada


<2
9 9 6 6 2 2 2
pivot = 2
3 3 3 <7 3 3 <5 3 3 >2
pivot = 5
5 5 5 5 5
11 11 2 2 6 >5
2 2 7
7 7 pivot = 7 12
12 12 9 >7
Falta regredir nas chamadas
6 6 8
8 8 11

Reparar que pivot já está ordenado

2007/08
A.E.D.
F.S.B. Ordenação de vectores : QuickSort
 Exemplificação do algoritmo
 Usando um pivot completamente arbitrário!

1ª chamada 2ª chamada 3ª chamada

9 9 6 6 2 2 2
pivot = 2
3 3 3 <7 3 3 <5 3 3
pivot = 5
5 5 5 5 5
11 11 2 2 6 >5
2 2 7
7 7 pivot = 7 12
12 12 9 >7
6 6 8
8 8 11
2007/08
A.E.D.
F.S.B. Ordenação de vectores : QuickSort
 Exemplificação do algoritmo
 Usando um pivot completamente arbitrário!

1ª chamada 2ª chamada 3ª chamada

9 9 6 6 2 2
3 3 3 <7 3 3 3
pivot = 5
5 5 5 5 5
11 11 2 2 6
2 2 7
7 7 pivot = 7 12 Vindo de outra chamada
12 12 9 >7
6 6 8
8 8 11

2007/08
A.E.D.
F.S.B. Ordenação de vectores : QuickSort
 Exemplificação do algoritmo
 Usando um pivot completamente arbitrário!

1ª chamada 2ª chamada

9 9 6 2 2
3 3 3 <7 3 3
pivot = 5
5 5 5 5 5
11 11 2 6 6
2 2 7
7 7 pivot = 7 12
12 12 9 >7
6 6 8
8 8 11
2007/08
A.E.D.
F.S.B. Ordenação de vectores : QuickSort
 Exemplificação do algoritmo
 Usando um pivot completamente arbitrário!

1ª chamada 2ª chamada

9 9 2 2
3 3 3 3
5 5 5 5
11 11 6 6
2 2 7
7 7 pivot = 7 8
12 12 9
6 6 11
8 8 12
Vindo de outra chamada

2007/08
A.E.D.
F.S.B. Ordenação de vectores : QuickSort
 Exemplificação do algoritmo
 Usando um pivot completamente arbitrário!

1ª chamada

2 2 2
3 3 3
5 5 5
6 6 6
7 7 7
8 8 pivot = 7 8
9 9 9
11 11 11
12 12 12
2007/08
A.E.D.
F.S.B. Ordenação de vectores : QuickSort
 Visto assim o QuickSort até é fácil de
compreender, mas há pontos ainda em aberto:
 Como se escolhe o pivot?
 Como se coloca o pivot no centro do vector?
 Como se divide o vector em maiores e menores?

2007/08
A.E.D.
F.S.B. Ordenação de vectores : QuickSort
 Escolha do pivot:
 Não se deve escolher o primeiro elemento
 Num vector já ordenado isso iria dividir o vector em dois
pedaços: um com um elemento (o pivot) e outro com o resto
dos elementos todos…
 Não se deve escolher o último
 Pelas mesmas razões
 Um muito utilizado é usar a mediana de três valores
 Os valores a utilizar são o primeiro, o último e o central
 Escolhe-se aquele que for o valor do meio
 Outra técnica é escolher um aleatoriamente
 Requer um gerador de números aleatórios
2007/08
A.E.D.
F.S.B. Ordenação de vectores : QuickSort
 Colocação do pivot no centro do vector:
 Normalmente coloca-se no final do vector
 Só depois da divisão em maiores e menores é que se
recoloca no meio
 Para isso troca-se o pivot com o penúltimo elemento do
vector

2007/08
A.E.D.
F.S.B. Ordenação de vectores : QuickSort
 Escolha do pivot:
 Pode ser feita com este método

int pivotMediana( int v[], int ini, int fim ) {

int centro = (ini + fim ) /2;

if( v[ini] > v[centro] ) // já se ordenam os 3 elementos


troca( v, ini, centro );
if( v[ini] > v[fim] )
troca( v, ini, fim );
if( v[centro] > v[fim] )
troca( v, centro, fim );

// valor mediano fica na posição central


// para preparar o vector deve-se trocar com penúltimo
// (lembrar que o último é maior que o do centro)
troca( v, centro, fim-1);

return v[ fim - 1 ]; // retorna o pivot


}
2007/08
A.E.D.
F.S.B. Ordenação de vectores : QuickSort
 O método anterior usou o método troca que
pode ser definido assim

void troca( int v[], int i, int j ) {


int aux = v[ i ];
v[ i ] = v[ j ];
v[ j ] = aux;
}

2007/08
A.E.D.
F.S.B. Ordenação de vectores : QuickSort
 Como se divide o vector em maiores e menores?
 Existem várias técnicas
 Uma muito usada é ter dois índices a percorrer o
vector
 Um da esquerda para a direita
 Outro da direita para a esquerda
 Quando o da esquerda detecta um maior que o pivot
pára
 Quando o da direita detecta um menor que o pivot
pára
 Quando ambos param trocam os seus valores
 Quando ambos se encontram é porque o vector já
está dividido
2007/08
A.E.D.
F.S.B. Ordenação de vectores : QuickSort
 Exemplificação do algoritmo de divisão em maiores e menores
 Usando um pivot mediana de 3

v[ini] > v[centro] trocam pivot está no centro Vector pronto para dividir
9 ini = 0 9 2 2 2 2
3 3 3 3 3 3
5 5 5 5 5 5
11 11 11 11 11 11
2 centro = 4 2 9 8 8 6
7 7 7 7 7 7
12 12 12 12 12 12
6 6 6 6 6 8
8 fim = 8 8 8 9 9 9

v[centro] > v[fim] trocam Trocar pivot com penúltimo


Reparar que o 9 já está
no lado dos maiores

2007/08
A.E.D.
F.S.B. Ordenação de vectores : QuickSort
 Exemplificação do algoritmo de divisão em maiores e menores
 Usando um pivot mediana de 3

Vector pronto deslocar primeiro i


para dividir depois deslocar j
2 i = ini = 0 2 i = 0 já se sabe que tem um valor menor, avança logo
3 3 i = 1 v[ i ] < pivot i segue
5 5 i = 2 v[ i ] < pivot i segue
11 11 i = 3 v[ i ] >= pivot i pára
6 6 Como i < j trocam-se os valores
7 7 j = 5 v[ j ] <= pivot j pára
12 12 j = 6 v[ j ] > pivot j avança
8 j = fim – 1 = 7 8 j = 7 já se sabe que é o pivot avança logo
9 9
2007/08
A.E.D.
F.S.B. Ordenação de vectores : QuickSort
 Exemplificação do algoritmo de divisão em maiores e menores
 Usando um pivot mediana de 3

Vector pronto recomeça i Trocar pivot com


para dividir posição em i Vector dividido
pára a divisão
2 i = ini = 0 2 2 2
3 3 3 3
5 5 5 5
11 7 7 7
6 6 i = 4 v[ i ] < pivot i segue 6 6
7 11 i = j = 5 a divisão está feita 11 8
12 12 12 12
8 j = fim – 1 = 7 8 8 11
9 9 9 9

2007/08
A.E.D.
F.S.B. Ordenação de vectores : QuickSort
 A divisão em maiores e menores pode ser feita
com este método
void divideMaioresMenores( int v[], int ini, int fim, int pivot ) {

int i = ini;
int j = fim -1;
while( i < j ) {
while( v[ ++i ] < pivot );
while( v[ --j ] > pivot );
if( i < j )
troca( v, i, j );
}

// recolocar o pivot no sitio


troca( v, i, fim - 1 );
}
2007/08
A.E.D.
F.S.B. Ordenação de vectores : QuickSort
 Últimas considerações
 Este algoritmo é muito sensível às várias escolhas
que se tem de fazer
 Pivot
 Método de divisão
 As escolhas erradas podem ditar uma grande
penalização na eficiência
 Como se viu no caso da escolha do pivot como sendo o
primeiro elemento do vector
 Para vectores pequenos é mais lento que o de
inserção
 Para valores de 5 a 20 elementos é melhor o de inserção
directa
 Muitas implementações do QuickSort colocam um limite

abaixo do qual aplicam o de inserção

2007/08
A.E.D.
F.S.B. Ordenação de vectores : QuickSort
 Tal como no MergeSort o algoritmo exige, pelo
menos, dois métodos:
 O que prepara a chamada recursiva
 O que faz as chamadas recursivas

void ordenaQuickSort( int v[] ) {

quickSortRec( v, 0, v.length -1 );

}
2007/08
A.E.D.
F.S.B. Ordenação de vectores : QuickSort
 O que faz as chamadas recursivas

void quickSortRec( int v[], int ini, int fim ) {


// Se tamanho do vector < limite de eficiência
// faz a ordenação por inserção
if( fim - ini < TAMANHO_EFICIENCIA ) {
ordenaInsercao( v, ini, fim );
return;
}

// determinar o pivot
int pivot = pivotMediana( v, ini, fim );

// dividir em menores e maiores


divideMaioresMenores( v, ini, fim, pivot );

quickSortRec( v, ini, i-1 ); // ordenar os menores


quickSortRec( v, i+1, fim ); // ordenar os maiores
}

2007/08
A.E.D.
F.S.B. Ordenação de vectores : BucketSort
 Mais rápido ainda que o QuickSort!
 Mas o QuickSort não era o mais rápido?
 Não é genérico!
 Só serve para valores numéricos inteiros positivos
 Embora com adaptações sirva para negativos
 O QuickSort serve para tudo, logo é o mais rápido dos
genéricos
 Temos de ter a certeza que os números nunca
são maiores que um dado valor
2007/08
A.E.D.
F.S.B. Ordenação de vectores : BucketSort
 Cria-se um vector com o tamanho do maior
número presente no vector a ordenar, chamado
vector de contagem
 Inicializa-se cada posição do vector de
contagem a zero
 Percorre-se o vector a ordenar
 Por cada elemento do vector incrementa-se no vector
de contagem a posição correspondente ao seu valor
 Exemplo: o número 5 iria fazer incrementar de 1 a posição 5
do vector de contagem
 No final é só alterar o vector original de acordo
com a contagem feita no vector de contagem

2007/08
A.E.D.
F.S.B. Ordenação de vectores : BuckerSort
 Exemplificação do algoritmo
 Assume-se que o valor mais alto que se pode ordenar é o 14
Vector de contagem,
com 15 posições
0
0
2 1 Ocorrência de 2 incrementa posição 2 do vector
3 1 Ocorrência de 3 incrementa posição 3 do vector
5 0
5 2 2 ocorrências de 5 incrementa duas vezes a posição 5 do vector
12 0
7 1 Ocorrência de 7 incrementa posição 7 do vector
12 1 Ocorrência de 8 incrementa posição 8 do vector
8 1 Ocorrência de 9 incrementa posição 8 do vector
9 0
2 2 ocorrências de 12 incrementa duas vezes a posição 12 do vector
0 Vector de contagem completo
0 Falta repor o vector de origem
0
2007/08
A.E.D.
F.S.B. Ordenação de vectores : BuckerSort
 Exemplificação do algoritmo
 Assume-se que o valor mais alto que se pode ordenar é o 14
Vector de contagem,
com 15 posições
0 Não há zeros nem uns no vector original
0
2 1 Copia 1 vez o 2 para o vector original
3 1 Copia 1 vez o 3 para o vector original
5 0
5 2 Copia 2 vezes o 5 para o vector original
7 0
8 1 Copia 1 vez o 7 para o vector original
9 1 Copia 1 vez o 8 para o vector original
12 1 Copia 1 vez o 9 para o vector original
12 0
2 Copia 2 vezes o 12 para o vector original
0
0
0

2007/08
A.E.D.
F.S.B. Ordenação de vectores : BucketSort
 Este algoritmo pode ser assim implementado

void ordenaBucketSort( int v[], int nMax ) {


// criação do vector de contagem, com nMax a ser parametrizado
int conta[] = new int[ nMax ];

// contar os valores dos vectores


for( int i = 0; i < v.length; i++ )
conta[ v[i] ]++;

// refazer para o vector original


int iOriginal = 0;
for( int i = 0; i < conta.length; i++ ) {
for( int k = 0; k < conta[ i ]; k++ ){
v[ iOriginal ] = i;
iOriginal++;
}
}
}

Das könnte Ihnen auch gefallen