Você está na página 1de 5

MC102 Introducao `a Programacao de Computadores

Mergesort e Quicksort
Felipe P.G. Bergo
Nesta aula apresentamos dois algoritmos de ordenacao recursivos: mergesort e quicksort. Ambos
tentam reduzir o problema de ordenacao a dois subproblemas de tamanhos similares, levando a
uma performance proporcional a nlog(n) em caso de sucesso.
1 Mergesort
Mergesort (ordenacao por intercala cao) divide o vetor de entrada em dois subvetores com metade
do tamanho do vetor original (em caso de tamanho mpar, um dos subvetores tera um elemento
a mais que o outro). Cada um dos subvetores e ordenado recursivamente. Os dois subvetores sao
intercalados em um vetor temporario. Mergesort garante que os dois subproblemas tem tamanho
n
2
, mas requer alocacao de memoria para o vetor temporario. O algoritmo do Mergesort e dado
abaixo:
Algoritmo 1 MergeSort
Entrada: Vetor V , ndice inicial a, ndice nal b.
Sada: Vetor V , ordenado.
1. Se a = b, retorne V .
2. Compute m
(a+b)
2
.
3. Ordene V [a . . . m] por MergeSort.
4. Ordene V [m + 1 . . . b] por MergeSort.
5. Faca i a, j m + 1 e k 0.
6. Aloque um vetor T[0 . . . (b a)].
7. Enquanto i < m + 1 ou j < b + 1 Fa ca
8. Se (i m e V [i] < V [j]) ou (j = b + 1) Entao
9. Faca T[k] V [i], incremente k e incremente i
10. Senao
11. Faca T[k] V [j], incremente k e incremente j.
12. Para i = a ate b Fa ca
13. V [i] T[i a].
14. Desaloque T.
15. Retorne V .
A funcao abaixo implementa o mergesort em C para ordenar vetores de inteiros:
1
void mergesort(int *v,int inicio,int fim) {
int i,j,k,m,*t;
if (inicio==fim) return;
// ordenacao recursiva das duas metades
m = (inicio+fim)/2;
mergesort(v,inicio,m);
mergesort(v,m+1,fim);
// intercalacao no vetor temporario t
i = inicio;
j = m+1;
k = 0;
t = (int *) malloc(sizeof(int) * (fim-inicio+1));
while(i<m+1 || j<fim+1) {
if (i==m+1) { // i passou do final da primeira metade, pegar v[j]
t[k] = v[j];
j++; k++;
} else if (j==fim+1) { // j passou do final da segunda metade, pegar v[i]
t[k] = v[i];
i++; k++;
} else if (v[i] < v[j]) { // v[i]<v[j], pegar v[i]
t[k] = v[i];
i++; k++;
} else { // v[j]<=v[i], pegar v[j]
t[k] = v[j];
j++; k++;
}
}
// copia vetor intercalado para o vetor original
for(i=inicio;i<=fim;i++)
v[i] = t[i-inicio];
free(t);
}
2 Quicksort
O algoritmo Quicksort nao requer armazenamento temporario, mas seu procedimento de particao
pode gerar subvetores de tamanhos diferentes. Quicksort escolhe um elemento pivot, e particiona
o vetor de tal forma que todos os elementos menores que o pivot quem `a esquerda, e todos os
elementos maiores ou iguais ao pivot quem `a direita. As duas particoes sao ordenadas recursiva-
2
mente, e o resultado e o vetor ordenado. No pior caso, quicksort leva tempo n
2
. No caso medio,
nlog(n). O quicksort pode ser expresso pelos dois algoritmos abaixo:
Algoritmo 2 QuickSort
Entrada: Vetor V , ndice inicial a, ndice nal b.
Sada: Vetor V , ordenado.
1. Se a < b
2. q Particiona(V ,a,b).
3. QuickSort(V ,a,q).
4. QuickSort(V ,q + 1,b).
5. Retorne V .
Algoritmo 3 Particiona
Entrada: Vetor V , ndice inicial a, ndice nal b.
Sada: q, ndice do ponto de particao.
1. Faca x V [a], i a 1 e j b + 1.
2. Enquanto verdadeiro Fa ca
3. Repita j j 1 ate que V [j] x
4. Repita i i + 1 ate que V [i] x
5. Se i < j Entao
6. Troque V [i] com V [j].
7. Senao retorne q = j.
E as funcoes abaixo implementam o quicksort em C:
int partition(int *v,int inicio,int fim) {
int x,i,j,t;
x = v[inicio];
i = inicio - 1;
j = fim + 1;
for(;;) {
do { j--; } while(v[j]>x);
do { i++; } while(v[i]<x);
if (i<j) {
t = v[i];
v[i] = v[j];
v[j] = t;
} else
return j;
3
}
}
void quicksort(int *v,int inicio,int fim) {
int q;
if (inicio < fim) {
q = partition(v,inicio,fim);
quicksort(v,inicio,q);
quicksort(v,q+1,fim);
}
}
3 Performance
Agora que os principais algoritmos de ordenacao foram apresentados, mostramos uma comparacao
entre eles. A Figura 1a mostra comparacoes entre os gracos das funcoes y = x (comportamento
linear), y = xlog(x) (comportamento log-linear) e y = x
2
(comportamento quadratico). Algoritmos
quadraticos sao tao piores que os lineares e log-lineares que as duas ultimas curvas cam pratica-
mente ilegveis. A Figura 1b mostra as curvas linear e log-linear isoladamente. Note que a curva
log-linear, visualmente, e facilmente confundida com comportamento linear.
0
5000
10000
15000
20000
25000
30000
35000
40000
0 50 100 150 200
T
N
Linear
Log-Linear
Quadratico
0
2000
4000
6000
8000
10000
12000
14000
16000
0 500 1000 1500 2000
T
N
Linear
Log-Linear
(a) (b)
Figura 1: Curvas tpicas de tempo vs. tamanho para algoritmos lineares, log-lineares e quadraticos.
Para testar os algoritmos, foi escrito um programa que aloca um e sorteia um vetor de 5000000
elementos inteiros aleatorios. Para diversos valores de n entre 0 e 5000000, cada algoritmo ordena
o maior n umero possvel de subvetores distintos com n elementos. Para os algoritmos quadraticos
executamos apenas ate n = 50000, por limitacao de tempo. O vetor inicial foi sorteado apenas
uma vez e todos os algoritmos tiveram que ordenar os mesmos dados (cada algoritmo trabalhou
sobre uma copia do vetor original). Testamos duas versoes do quicksort: Quick Sort 1 usa sempre o
primeiro elemento do sub-vetor como pivo. Quick Sort 2 usa a mediana dos 3 primeiros elementos.
O codigo-fonte do programa esta disponvel como perf.c na pagina do curso. A Figura 2 mostra
os resultados, obtidos em um Athlon64 3200+ (2.0 GHz).
Como esperado, Bubble Sort e o pior dos algoritmos quadraticos. Na Figura 2a sequer conseguimos
4
0
1
2
3
4
5
6
7
8
0 10000 20000 30000 40000 50000
T

(
s
e
g
u
n
d
o
s
)
N
Bubble Sort
Selection Sort
Insertion Sort
Merge Sort
Quick Sort 1
Quick Sort 2
0
0.002
0.004
0.006
0.008
0.01
0.012
0.014
0 10000 20000 30000 40000 50000
T

(
s
e
g
u
n
d
o
s
)
N
Merge Sort
Quick Sort 1
Quick Sort 2
(a) (b)
0
0.2
0.4
0.6
0.8
1
1.2
1.4
1.6
1.8
2
0 1e+06 2e+06 3e+06 4e+06 5e+06
T

(
s
e
g
u
n
d
o
s
)
N
Merge Sort
Quick Sort 1
Quick Sort 2
0
0.01
0.02
0.03
0.04
0.05
0.06
0 1000 2000 3000 4000 5000
T

(
s
e
g
u
n
d
o
s
)
N
Bubble Sort
Selection Sort
Insertion Sort
Merge Sort
Quick Sort 1
Quick Sort 2
(c) (d)
Figura 2: Comparacao da performance dos algoritmos de ordenacao.
ver os resultados do Merge Sort e Quick Sort, devido `a diferenca de performance entre algoritmos
quadraticos e log-lineares. As Figuras 2b e 2c mostram Merge Sort e Quick Sort isoladamente.
Note que o uso da mediana de 3 nao teve efeito no Quick Sort para dados aleatorios. Em algumas
situacoes, com dados viciados, o uso da mediana poderia evitar comportamento quadratico do
Quick Sort. A Figura 2d mostra a performance para n < 5000: para pequenos vetores, a escolha de
um algoritmo ruim vai fazer seu programa perder apenas alguns decimos de segundo, e e razoavel
escolher um algoritmo ruim porem mais simples de implementar. A Figura 2a deve deixar claro
que, para vetores grandes, qualquer algoritmo log-linear e muito melhor que qualquer algoritmo
quadratico. E a Figura 2b mostra que, embora Mergesort garanta log-linearidade, na pratica o
Quicksort e mais eciente.
A Tabela abaixo mostra o n umero de linhas (excluindo linhas em branco e de comentario) usadas
na implementacao de cada algoritmo.
Algoritmo Linhas
Bubble Sort 9
Selection Sort 12
Insertion Sort 10
Merge Sort 27
Quick Sort 1 20
Quick Sort 2 26
5

Você também pode gostar