You are on page 1of 50

QuickSort

Estrutura de Dados II
Jairo Francisco de Souza
Particionamento

Mecanismo principal dentro do algoritmo do


QuickSort

Para particionar um determinado conjunto de


dados, separamos de um lado todos os itens cuja as
chaves sejam maiores que um determinado valor, e
do outro lado, colocamos todos os itens cuja as
chaves sejam menores que um determinado valor

Ex: Dividir as fichas de empregados entre quem


mora a menos de 15km de distncia da empresa e
quem mora a uma distncia acima de 15km
Particionamento
Particionamento
Particionamento

A linha horizontal no exemplo anterior representa seu


valor piv, que exatamente o valor utilizado para que
possam ser separados os dois grupos de valores (um
grupo de valores menores e um grupo de valores
maiores que o piv)

No QuickSort este piv uma chave do vetor de


ordenao escolhida respeitando alguns critrios

Pode-se escolher qualquer valor para o piv,


dependendo do modo que sero construdas as
parties
Particionamento

Apesar de termos dois grupos de valores, no


quer dizer que os valores estejam ordenados
nestes grupos.
Porm, s o fato de estarem separados pelo
piv numa classificao de maior/menor que o
piv, j facilita o trabalho de ordenao.
A cada passo que um novo piv escolhido os
grupos ficam mais ordenados que antes
Algoritmo de Particionamento

O algoritmo trabalha comeando com 2


ponteiros, um em cada ponta do array
O ponteiro da esquerda leftPtr move-se para
a direita e o ponteiro da direita rightPtr move-
se para a esquerda
leftPtr inicializado com o ndice zero e ser
incrementado e rightPtr inicializado com
ndice do ltimo elemento do vetor e ser
decrementado
Parada e troca de valores
Quando o leftPtr encontra um item de menor valor que
o piv, ele incrementado j que o item est na
posio correta. Entretanto, se encontrar um item de
maior valor que o piv, ele pra.
Igualmente, quando o rightPtr encontra um item de
maior valor que o piv, ele decrementado j que o
item est na posio correta. Entretanto, se encontra
um item de menor valor que o piv, ele pra.
Quando ambos os ponteiros param, necessrio
fazer a troca dos dois elementos encontrados nas
posies erradas.
Parada e troca de valores
Tratando excees
E se todos os elementos so menores que o
piv?
O ponteiro leftPtr ir percorrer todo o array at ultrapassar seu limite e
disparar uma exceo do tipo Array Index Out of Bounds!
Para resolver basta adicionarmos mais uma condio nos nossos while!
Troca dos elementos
Exemplo

Particionar a seguinte lista com piv = 15:

2 23 89 7 14 35

LP RP
Exemplo

piv = 15:

2 23 89 7 14 35

LP RP

23 > 15 logo LP pra e RP comea a se mover!


Exemplo

piv = 15:

2 23 89 7 14 35

LP RP

14 < 15 logo RP pra! Logo necessrio fazer a troca dos elementos: swap(1,4)
Exemplo

piv = 15:

2 14 89 7 23 35

LP RP

O LP volta a caminhar no vetor!


Exemplo

piv = 15:

2 14 89 7 23 35

LP RP

89 > 15 logo LP pra e RP volta a se mover!


Exemplo

piv = 15:

2 14 89 7 23 35

LP RP

7 < 15 logo RP pra! Logo necessrio fazer a troca dos elementos: swap(2,3)
Exemplo

piv = 15:

2 14 7 89 23 35

LP RP

O LP volta a caminhar no vetor!


Exemplo

piv = 15:

2 14 7 89 23 35

LP RP

89 > 15 logo LP pra e RP volta a se mover!


Exemplo

piv = 15:

2 14 7 89 23 35

RP LP

7 < 15 logo RP pra! A condio LP >= RP satisfeita e o particionamento termina!


Algoritmo
Eficincia do Particionamento
Roda em O(n)
Nmero de comparaes independente de como os
dados esto arranjados
Nmero de trocas, por outro lado, dependente do
arranjo das informaes:
Se a ordem est invertida e o piv divide exatamente em dois
conjuntos de mesmo tamanho temos N/2 trocas
No caso de dados randmico h um pouco menos de (N/2
trocas)
Exerccio

Particione o seguinte conjunto de valores mostrando passo a passo o processo .


`
PIV=99:

149 192 47 152 159 195 61 66 17 167 118 64 27 80 30 105


QuickSort
Algoritmo mais popular de ordenao
Na maioria dos casos ele roda em O(NlogN) para
ordenaes internas ou em memria. Para
ordenar informaes em arquivos em disco
existem mtodos melhores.
Algoritmo criado em 1962 por C.A.R. Hoare
Particionamento a base do algoritmo e
chamado de maneira recursiva
importante ainda a escolha do piv e como
feito o processo de ordenao
QuickSort
QuickSort

3 passos bsicos:
Particionamento do array ou subarray em um
grupo de chaves menores (lado esquerdo) e um
grupo de chaves maiores (lado direito)
Chamada recursiva para ordenar/particionar o
lado esquerdo
Chamada recursiva para ordenar/particionar o
lado direito
QuickSort
Aps o particionamento temos um grupo dentro do array
do lado esquerdo com valores menores e um grupo dentro
do array do lado direito com valores maiores. Se
ordenarmos cada um desses grupos, temos no final um
array totalmente ordenado
Como orden-los? Utilizando as chamadas recursivas para
particionar os subarrays. O mtodo recebe como
parmetros onde comea e onde termina cada subarray
que deve ser ordenado. O mtodo checa antes se o
subarray contm somente um elemento, este o critrio
de parada para as chamadas recursivas
QuickSort

Se o subarray contm dois ou mais elementos, o


algoritmo chama o mtodo partitionInt() para
particion-lo. Este nmero retorna o ndice da
partio
O ndice da partio marca exatamente o limite
entre os dois lados do subarray (um lado com
valores menores e outro lado com valores
maiores)
QuickSort

array no particionado
42 89 63 12 94 27 78 3 50 36

partio
subarray esquerdo subarray direito

3 27 12 36 63 94 89 78 42 50

j ordenado
ser ordenado pela ser ordenado pela
primeira chamada segunda chamada
recursiva de recQuickSort() recursiva de recQuickSort()
QuickSort

Uma vez o array particionado, e a chamada


recursiva ao mtodo recQuickSort() para o lado
esquerdo os parmetros so left e partition-1 j
para o lado direito so partition+1. E o ndice
partition?
PIV! Como escolher? E seu papel?
Escolha do Piv

O piv deve ser algum dos valores que compem o


array
O piv pode ser escolhido aleatoriamente. Para
simplificar, vamos escolher como piv sempre o
elemento que est na extrema direita de todo subarray
que ser particionado
Aps o particionamento, se o piv inserido no limite
entre os dois subarrays particionados, ele j estar
automaticamente em sua posio correta na
ordenao
Escolha do Piv

array no particionado
42 89 63 12 94 27 78 3 50 36

piv
posio correta
do piv
subarray particionado
esquerdo subarray particionado direito
3 27 12 63 94 89 78 42 50 36
Escolha do Piv

Como inserir ento o piv no seu lugar correto?


Deslocando todos os outros elementos maiores
que ele uma posio no array?
Uma possibilidade simplesmente trocar o piv
pelo primeiro elemento do subarray que s
possui valores maiores que o piv
Escolha do Piv

subarray esquerdo subarray direito piv

42 Piv = 36
27 12 63 94 89 78 42 50 36
Aps o
particionamento
troca-se o 36 pelo 63
que o primeiro
elemento do grupo
dos valores maiores
3 27 12 36 94 89 78 42 50 63 que o piv
subarray esquerdo subarray direito
piv
Novo Algoritmo com Piv
Novo Algoritmo Particionamento
2
Degenerao para O(n )

O que acontece quando pegamos um array para


ordenar e ele est em ordem decrescente?
Problema est na seleo do piv. O ideal que
o piv seja um valor mediano. Sendo assim,
haveria duas parties com tamanhos bem
prximos e o algoritmo funcionaria sempre
muito rpido
Piv Mdia

Muitos mtodos so estudados para se alcanar


o melhor piv
O mtodo precisa ser simples para no
degenerar o algoritmo e ao mesmo tempo ter
uma boa chance de evitar os valores extremos
Poderamos examinar todo o array e encontrar
o valor mediano dentre todos?
Piv Mdia

Uma soluo simples e atraente obter o


valor mediano entre trs elementos do array:

1 elemento

Elemento no meio do array

ltimo elemento

Processo chamado mdia-dos-trs



Agilidade no processo e possui altas taxas de sucesso

Ganho de desempenho no algoritmo
Piv mdia

left center right

44 86 29
antes de ordenar

left center right

29 44 86
depois de ordenar
se torna o piv
Piv Mdia

O teste rightPtr > left do segundo loop dentro do


mtodo partitionIt pode ser retirado
O mtodo mdia-de-trs, alm de escolher o piv,
ainda ordena estes 3 elementos
Ganho nas parties?
Assim, alm de evitar a degradao para O(n2), ainda
ganha-se tempo nos loops internos (menos uma
comparao em cada iterao) e reduz a quantidade de
elementos para serem particionados
Algoritmo
Algoritmo
Algoritmo
Algoritmo
Algoritmo

necessrio um algoritmo especfico para


ordenar um array de at 3 elementos pois
utilizando a mdia-de-trs s possvel utilizar a
partir de 4 elementos
Segundo Knuth, o ideal que arrays com
tamanho inferior a 10 sejam ordenados
utilizando o InsertionSort, caso contrrio o
QuickSort ordena normalmente
Algoritmo
Recurso?

Alguns programadores/autores discutem a


remoo da recurso do QuickSort e substituir
por uma abordagem iterativa com loops
Apesar disto, esta idia pouco adotada
atualmente pois as linguagens mais modernas
no encontram gargalos nesse tipo de situao,
muito menos o hardware
Eficincia do algoritmo

Complexidade: O(NlogN) para o melhor caso e


para o caso mdio
2
No pior caso, pode degenerar para O(n )
Correspondente aos algoritmos de diviso e
conquista como o MergeSort tambm
Estudo da estabilidade

O algoritmo considerado instvel, pois h a


possibilidade de elementos com mesma chave
mudar de posio no processo de ordenao

O QuickSort baseado no particionamento de


vetores.

Ento, considerando o vetor [0 21 3 22 5 1] e o piv


como 2, teremos o seguinte particionamento:

Encontrando os ponteiros: [0 21 3 22 5 1]

Alterando as posies: [0 1 3 22 5 21]

You might also like