Você está na página 1de 27

QuickSort

Algoritmos e Estuturas de Dados


Inverno 2006

Ctia Vaz

QuickSort
Algoritmo do tipo dividir para conquistar Ideia do algoritmo: efectuar partio dos dados e ordenar as vrias partes independentemente (de forma recursiva) posicionamento da partio a efectuar depende dos dados de entrada processo de partio crtico uma vez efectuada a partio, cada uma das partes pode por sua vez ser ordenada pelo mesmo algoritmo .
Ctia Vaz
2

QuickSort-partio
public static void quicksort(int a[], int left, int right){ int i; if (right <= left) return; i = partition(a, left, right); quicksort(a, left, i-1); quicksort(a, i+1, right); }

Processo de partio rearranja os dados de forma a que as trs condies seguintes sejam vlidas (de a[left] a a[right]):
o elemento a[i], para algum i, fica, aps a partio, na sua posio final; nenhum dos elementos em a[left] a[i-1] maior do que a[i]; nenhum dos elementos em a[i+1] a[right] menor do que a[i]. Ctia Vaz
3

QuickSort-partio
Para cada processo de partio, pelo menos um elemento fica na sua posio final. Aps partio, o array fica sub-dividido em duas partes que podem ser ordenadas separadamente A ordenao completa conseguida atravs de partio + aplicao recursiva do algoritmo aos dois subconjuntos de dados da resultantes.

Ctia Vaz

QuickSort-partio
Estratgia para a partio escolher a[right] arbitrariamente para ser o elemento de partio percorrer o array a partir da esquerda at encontrar um elemento maior que ou igual ao elemento de partio (a[right]) percorrer o array a partir da direita at encontrar um elemento menor que ou igual ao elemento de partio (a[right])
trocamos as posies destes dois elementos!

procedimento continua at nenhum elemento esquerda de a[right] ser maior que ele, e nenhum elemento direita de a[right] ser menor que ele
completa-se trocando a[right] com o elemento mais esquerda do sub-array da direita Ctia Vaz

QuickSort-partio
public int int v = for static int partition(int a[], int left, int right){ i, j;//i da esquerda para a direita, j ao contrrio v; //elemento de partio a[right]; i = left-1; j = right; (;;) { while (less(a[++i], v)) ; while (less(v, a[--j])) if (j == left) break; if (i >= j) break; exch(a[i], a[j]);

} exch(a[i], a[right]); return i; }

Ctia Vaz

QuickSort-partio
Processo de partio no estvel
qualquer chave pode ser movida para trs de vrias outras chaves iguais a si (que ainda no foram examinadas)

A eficincia do processo de ordenao depende de como a partio divide os dados (do elemento de partio)
ser tanto mais equilibrada quanto mais perto este elemento estiver do meio do array na sua posio final

Ctia Vaz

QuickSort-caractersticas
Pode ser muito ineficiente em casos patolgicos!
Propriedade: quicksort usa cerca de N2/2 comparaes no pior caso.
Demonstrao: se o array j estiver ordenado, todas as parties degeneram e o programa chama-se a si prprio N vezes; o nmero de comparaes de N + (N-1) + (N-2) + + 2 + 1 = (N + 1) N / 2 (mesma situao se o ficheiro estiver ordenado por ordem inversa) Nota: No apenas o tempo necessrio para a execuo do algoritmo cresce quadraticamente como o espao necessrio para o processo recursivo de cerca de N o que inaceitvel para ficheiros grandes.

Ctia Vaz

QuickSort-caractersticas
Melhor caso: quando cada partio divide o ficheiro de entrada exactamente em metade
nmero de comparaes usadas por quicksort satisfaz a recurso de dividir para conquistar C(N)= 2 C( N /2) + N

e logo

C(N) =O( N log N)

Ctia Vaz

QuickSort-caractersticas
Propriedade: quicksort usa cerca de 2N lg N comparaes em mdia Demonstrao: A frmula de recorrncia exacta para o nmero de comparaes utilizado por quicksort para ordenar N nmeros distintos aleatoriamente posicionados

o termo N+1 cobre o custo de comparar o elemento de partio com os restantes (2 comparaes extra: i e j cruzamse) cada elemento tem probabilidade 1/N de ser o elemento de partio aps o que ficamos com duas sub-arrays de tamanhos k-1 e N-k
Ctia Vaz
10

QuickSort-caractersticas
Esta anlise assume que os dados esto aleatoriamente ordenados e tm chaves diferentes
pode ser lento em situaes em que as chaves no so distintas ou que os dados no esto aleatoriamente ordenados

O algoritmo pode ser melhorado para reduzir a probabilidade que um caso mau ocorra.

Ctia Vaz

11

QuickSort-caractersticas
Questes mais relevantes:
possvel reduo de desempenho devido ao uso de recurso tempo de execuo dependente dos dados de entrada tempo de execuo quadrtico no pior caso espao/memria necessrio no pior caso linear
um problema srio (para uma estrutura de dados de grandes dimenses)

Problema do espao est associado ao uso de recurso:


recurso implica chamada a funo e logo a carregar dados na pilha/stack do computador
Ctia Vaz

12

QuickSort- verso no
recursiva
Usamos uma pilha (stack) explcita
pilha contm trabalho a ser processado, na forma de subarrays a ordenar quando precisamos de um sub-array para processar tiramola da pilha (i.e.fazemos um pop() do stack) por cada partio criamos duas sub-arrays e colocamos ambas na pilha (i.e. fazemos dois push() para o stack) substitui a pilha do computador que usado na implementao recursiva

Conduz a uma verso no recursiva de quicksort()

Ctia Vaz

13

QuickSort
verso no recursiva de quicksort()
verifica os tamanhos dos dois sub-arrays e coloca o maior deles primeiro na pilha (e o menor depois; logo o menor retirado e tratado primeiro) ordem de processamento dos sub-arrays no afecta a correcta operao da funo ou o tempo de processamento mas afecta o tamanho da pilha

Ctia Vaz

14

QuickSort-verso no recursiva
static void quicksort(int a[], int left, int right){ intStack s=new intStack(50); s.push(left);s.push(right) while (!s.empty()) { right = s.pop(); left = s.pop(); if (right <= left) continue; i = partition(a, left, right); if (i-left > right-i){ s.push(left); s.push(i-1);} s.push(i+1);s.push(right); if (i-left <= right-i){ s.push(left);s.push(i-1);} } }

Ctia Vaz

15

QuickSort-verso no recursiva
A estratgia de colocar o maior dos sub-arrays primeiro na pilha
garante que cada entrada na pilha no maior do que metade da que estiver antes dela na pilha pilha apenas ocupa lg N no pior caso
que ocorre agora quando a partio for sempre no meio da tabela em ficheiros aleatrios o tamanho mximo da pilha bastante menor

Propriedade: se a menor dos dois sub-arrays for ordenado primeiro, a pilha nunca necessita mais do que lg N entradas quando quicksort usado para ordenar N elementos.
Demonstrao: no pior caso o tamanho da pilha inferior a T(N) em que T(N) satisfaz a recorrncia T(N) = T (|N/2|) + 1 (T(0) = T(1) = 0)
Ctia Vaz

16

QuickSort-verso no
recursiva
Propriedade: se a menor dos dois sub-arrays for ordenado primeiro, a pilha nunca necessita mais do que lg N entradas quando quicksort usado para ordenar N elementos. Demonstrao: no pior caso o tamanho da pilha inferior a T(N) em que T(N) satisfaz a recorrncia T(N) = T (|N/2|) + 1 (T(0) = T(1) = 0)

Ctia Vaz

17

QuickSort- melhoramentos
Algoritmo pode ainda ser melhorado
porqu colocar ambas os sub-arrays na pilha se um deles de imediato retirado teste de right <= left feito assim que os sub-arrays saem da pilha
seria melhor nunca as l ter colocado!

ordenao de sub-arrays de pequenas dimenses pode ser efectuada de forma mais eficiente como escolher correctamente o elemento de partio? Como melhorar o desempenho se os dados tiverem um grande nmero de chaves repetidas?
Ctia Vaz

18

QuickSort- melhoramentos
Pequenos ficheiros/sub-arrays
pode melhorar-se ao mudar o teste no incio da funo recursiva para uma chamada a insertion sort
if (right-left <= M) insertion(a, left, right)

em que M um parmetro a definir na implementao

algoritmo hbrido: bom mtodo em geral.

Ctia Vaz

19

QuickSort- melhoramentos
Utilizar um elemento de partio que com alta probabilidade divida o array pela metade
pode-se usar um elemento aleatoriamente escolhido
evita o pior caso (i.e. pior caso tem baixa probabilidade de acontecer) um exemplo de um algoritmo probabilstico

pode-se escolher alguns (ex: trs) elementos do array e usar a mediana dos trs como elemento de partio
escolhendo os trs elementos da esquerda, meio e direita da tabela podemos incorporar sentinelas na ordenao ordenamos os trs elementos, depois trocamos o do meio com a[right-1] e corremos o algoritmo de partio em a[left+1] a[right-2] este melhoramento chama-se o mtodo da mediana de trs. Ctia Vaz

20

QuickSort- melhoramentos
Mtodo da mediana de trs melhora quicksort por trs razes
o pior caso mais improvvel de acontecer na prtica
dois dos trs elementos teriam de ser dos maiores ou menores do array e isto teria de acontecer constantemente a todos os nveis de partio

reduz o tempo mdio de execuo do algoritmo embora apenas por cerca de 5% caso particular de mtodos em que se faz amostragem dos dados para estimar as suas propriedades

Conjuntamente com o mtodo de tratar de pequenos arrays pode dar ganhos de 20 a 25%
Ctia Vaz
21

QuickSort- estudo emprico

Quicksort cerca de 2 vezes mais rpido que shellsort para arrays grandes aleatoriamente ordenados. Usando insertion para pequenos arrays e a estratgia de
mediana-de-trs melhoram cada um a eficincia por um factor de 10%
Ctia Vaz
22

QuickSort- chaves duplicadas


Arrays com um grande nmero de chaves duplicadas
so frequentes na prtica
desempenho de quicksort pode ser substancialmente melhorado se
todas as chaves forem iguais
quicksort mesmo assim faz N lg N comparaes

houver duas chaves distintas


reduz-se ao problema anterior para cada sub-array

natureza recursiva de quicksort garante que haver frequentemente sub-arrays de items com poucas chaves uma possibilidade dividir o array em trs partes
cada uma para chaves menores, iguais e maiores que o elemento de partio

Ctia Vaz

23

QuickSort- chaves duplicadas


Soluo: fazer uma partio em trs partes
manter chaves iguais ao elemento de partio que so encontradas no sub-array da esquerda do lado esquerdo do array manter chaves iguais ao elemento de partio que so encontradas no sub-array da direita do lado direito do array

left

right

Quando os ndices de pesquisa se cruzam sabemos onde esto os elementos iguais ao de partio e fcil coloc-los em posio
trabalho extra para chaves duplicadas proporcional ao nmero de chaves duplicadas: funciona bem se no houver chaves duplicadas linear quando h um nmero constante de chaves Ctia Vaz

24

QuickSort- partio em trs


static void quicksort(int a[], int left, int right){ int i, j, k, p, q, v; if (right <= left) return; v = a[right]; i = left-1; j = right; p = left-1; q = right; for (;;) { while (less(a[++i], v)) ; while (less(v, a[--j])) if (j == left) break; if (i >= j) break; exch(a[i], a[j]); if (equal(a[i],v)) { p++; exch(a[p],a[i]);} if (equal(v,a[j])) { q--; exch(a[q],a[j]);} } exch(a[i], a[right]); j = i-1; i = i+1; for (k = left ; k < p; k++, j--) exch(a[k], a[j]); for (k = right-1; k > q; k--, i++) exch(a[k], a[i]); quicksort(a, left, j); quicksort(a, i, right); }

Ctia Vaz

25

Juno versus Partio


Quicksort baseado na operao de partio
efectuada uma partio e quando as duas metades do array esto ordenadas, o array est ordenado

Operao complementar de juno ( merge )


combinar dois arrays para obter um, maior, ordenado dividir os arrays em duas partes para serem ordenados e depois combinar as partes de forma a que o array total fique ordenado

mergesort

Mergesort: de um ficheiro de N elementos feito em


tempo proporcional a N log N, independentemente dos dados!! Ctia Vaz
26

MergeSort
Propriedade: A ordenao de um array de N elementos utilizando
o algoritmo Mergesort feito em tempo proporcional a N log N, independentemente dos dados!! No entanto requer espao extra proporcional a N dados apenas definem a ordem em que os elementos so processados nas junes um algoritmo estvel se a juno o for propriedade que muitas vezes faz com que seja escolhido! Normalmente implementado de forma a aceder aos dados sequencialmente por vezes o nico processo de acesso muito usado para ordenao de listas ligadas
Ctia Vaz
27

Você também pode gostar