Quicksort Parte2

5
Quicksort básico Agora que resolvemos o problema da separação, podemos cuidar do Quicksort propriamente dito. O algoritmo usa a estratégia da divisão e conquista e tem a aparência de um Mergesort ao contrário: // A função recebe um vetor v[p..r], com p <= r+1, // e rearranja o vetor em ordem crescente. void quicksort( int v[], int p, int r) { int j; // 1 if (p < r) { // 2 j = separa( v, p, r); // 3 quicksort( v, p, j-1); // 4 quicksort( v, j+1, r); // 5 } } (Note que a função está correta mesmo quando p > r, ou seja, quando o vetor está vazio.) Exercícios 3 1. Que acontece se trocarmos p < r por p != r na linha 2 do quicksort? 2. Que acontece se trocarmos j-1 por j na linha 4 do quicksort? Que acontece se trocarmos j+1 por j na linha 5 do código? 3. Submeta o vetor 77 55 33 99 indexado por 1..4 à função quicksort. Teremos a seguinte sequência de invocações da função (observe a indentação): 4. quicksort( v,1,4) 5. quicksort( v,1,2) 6. quicksort( v,1,0) 7. quicksort( v,2,2) 8. quicksort( v,4,4) Repita o exercício com o vetor 55 44 22 11 66 33 indexado por 1..6. 9. Tail recursion. Verifique que a segunda invocação da função quicksort (linha 5 do código) pode ser eliminada se trocarmos o if por um while: 10. void quicksrt( int v[], int p, int r) { 11. int j; 12. while (p < r) { 13. j = separa( v, p, r); 14. quicksrt( v, p, j-1); 15. p = j + 1; 16. } 17. } 18. A função quicksort produz uma ordenação estável do vetor? 19. Discuta a seguinte implementação do algoritmo Quicksort. A função só se aplica a vetores v[p..r] com p < r. 20. void qcksrt( int v[], int p, int r) { 21. int j; 22. j = separa( v, p, r); 23. if (p < j-1) qcksrt( v, p, j-1);

description

Agora que resolvemos o problema da separação, podemos cuidar do Quicksort propriamente dito. O algoritmo usa a estratégia da divisão e conquista e tem a aparência de um Mergesort ao contrário: // A função recebe um vetor v[p..r], com p // e rearranja o vetor em ordem crescente.

Transcript of Quicksort Parte2

  • Quicksort bsico

    Agora que resolvemos o problema da separao, podemos cuidar do Quicksort

    propriamente dito. O algoritmo usa a estratgia da diviso e conquista e tem a aparncia

    de um Mergesort ao contrrio:

    // A funo recebe um vetor v[p..r], com p r, ou seja, quando o vetor est

    vazio.)

    Exerccios 3

    1. Que acontece se trocarmos p < r por p != r na linha 2 do quicksort? 2. Que acontece se trocarmos j-1 por j na linha 4 do quicksort? Que acontece se

    trocarmos j+1 por j na linha 5 do cdigo? 3. Submeta o vetor 77 55 33 99 indexado por 1..4 funo quicksort. Teremos

    a seguinte sequncia de invocaes da funo (observe a indentao): 4. quicksort( v,1,4) 5. quicksort( v,1,2) 6. quicksort( v,1,0) 7. quicksort( v,2,2) 8. quicksort( v,4,4)

    Repita o exerccio com o vetor 55 44 22 11 66 33 indexado por 1..6.

    9. Tail recursion. Verifique que a segunda invocao da funo quicksort (linha 5 do cdigo) pode ser eliminada se trocarmos o if por um while:

    10. void quicksrt( int v[], int p, int r) { 11. int j; 12. while (p < r) { 13. j = separa( v, p, r); 14. quicksrt( v, p, j-1); 15. p = j + 1; 16. } 17. }

    18. A funo quicksort produz uma ordenao estvel do vetor? 19. Discuta a seguinte implementao do algoritmo Quicksort. A funo s se aplica a

    vetores v[p..r] com p < r. 20. void qcksrt( int v[], int p, int r) { 21. int j; 22. j = separa( v, p, r); 23. if (p < j-1) qcksrt( v, p, j-1);

  • 24. if (j+1 < r) qcksrt( v, j+1, r); 25. }

    26. Formulao alternativa da separao. Suponha dada uma implementao da funo separa que funciona assim: rearranja v[p..r] e devolve um ndice j tal que v[p..j] v[j+1..r]. Escreva uma verso do algoritmo Quicksort que use essa implementao do separa. Que restries devem ser impostas sobre j?

    27. Verso Iterativa. Escreva uma verso no recursiva do algoritmo Quicksort. [Soluo] 28. Quicksort Aleatorizado. Escreva uma verso aleatorizada (= randomized) do algoritmo

    Quicksort.

    Animaes do Quicksort

    Animao do Quicksort produzida por Mike Bostock (veja tambm uma visualizao esttica, uma variante, e uma outra forma de visualizao).

    Sorting Algorithms Animation by David R. Martin. Demonstrao animada do Quicksort, copiada da pgina da disciplina COS226 de

    R. Sedgewick (Universidade de Princeton). Animao de algoritmos de ordenao de Nicholas Andr Pinho de Oliveira. Quick-sort with Hungarian (Kkllmenti legnyes) folk dance, created at Sapientia

    University (Romania).

    Desempenho do Quicksort bsico

    O consumo de tempo da funo quicksort proporcional ao nmero de comparaes

    entre elementos do vetor. Se o ndice j devolvido por separa estiver sempre mais ou

    menos a meio caminho entre p e r, o nmero de comparaes ser aproximadamente n

    log n, sendo n o nmero de elementos do vetor. Se o vetor j estiver ordenado ou quase ordenado, o nmero de comparaes estar na ordem de

    n2.

    Portanto, o pior caso do Quicksort no melhor que o dos algoritmos elementares.

    Felizmente, o pior caso muito raro: em mdia, o consumo de tempo do quicksort

    proporcional a

    n log n .

    (Veja detalhes na minha pgina Anlise do Quicksort.)

    Altura da pilha de execuo do Quicksort

    Na verso bsica do Quicksort, o cdigo cuida imediatamente do subvetor v[p..j-1] e

    trata do subvetor v[j+1..r] somente depois que v[p..j-1] estiver ordenado.

    Dependendo do valor de j nas sucessivas invocaes da funo, a pilha de execuo

    pode crescer muito, atingindo altura igual ao nmero de elementos do vetor. (Isso

    acontece, por exemplo, se o vetor estiver em ordem decrescente.) O fenmeno no

    afeta o consumo de tempo do algoritmo, mas pode esgotar o espao de memria. Para

    controlar o crescimento da pilha de execuo preciso tomar duas providncias:

  • 1. cuidar primeiro do menor dos subvetores v[p..j-1] e v[j+1..r] e 2. eliminar a segunda invocao recursiva da funo (veja exerccio acima).

    Se adotarmos estas providncias, o tamanho do subvetor que est no topo da pilha de

    execuo ser menor que a metade do tamanho do subvetor que est logo abaixo na

    pilha. De modo mais geral, o subvetor que est em qualquer das posies da pilha de

    execuo ser menor que metade do subvetor que est imediatamente abaixo. Assim, se

    a funo for aplicada a um vetor com n elementos, a altura da pilha no passar de log

    n.

    // A funo rearranja o vetor v[p..r], com p

  • 18. } 19. quick_FlipFlop( v, p, i-1); 20. quick_FlipFlop( v, i+1, r); 21. } 22. }

    23. A verso abaixo (veja livro de Cormen, Leiserson e Rivest) comea por rearranjar v[p..r] de modo que v[p..j] v[j+1..r] e p j < r (compare com o resultado da separao feita acima). Note que os vetores v[p..j] e v[j+1..r] so ambos estritamente menores que o vetor original.

    24. // A funo rearranja o vetor v[p..r], com p c); 35. do ++i; while (v[i] < c); 36. if (i >= j) break; 37. t = v[i], v[i] = v[j], v[j] = t; 38. } 39. quick_CLR( v, p, j); 40. quick_CLR( v, j+1, r); 41. } 42. }

    43. Eis outra implementao. (Se no me engano, ela est no livro de Sedgewick.) 44. // A funo rearranja o vetor v[p..r], com p

  • 70. while (v[++i] < c) ; 71. while (c < v[--j]) if (j == p) break; 72. if (i > j) break; 73. troca( v[i], v[j]); 74. } 75. troca( v[i], v[r]); 76. quick_S2( v, p, j); 77. quick_S2( v, i+1, r);

    }

    }