Merge Sort

5
Mergesort: ordenação por intercalação Nosso problema: Rearranjar um vetor v[0 .. n-1] de tal modo que ele fique em ordem crescente , ou seja, de tal modo que tenhamos v[0] ≤ . . . ≤ v[n-1]. Já analisamos alguns algoritmos simples para esse problema que consomem tempo proporcional a n 2 . Vamos examinar agora um algoritmo mais complexo mas bem mais rápido. Intercalação de vetores ordenados Antes de resolver nosso problema principal é preciso resolver o seguinte problema da intercalação (= merge): dados vetores crescentes v[p .. q-1] e v[q .. r-1], rearranjar v[p .. r-1] em ordem crescente. p q-1 q r-1 111 333 555 555 777 999 999 222 444 777 888 É fácil resolver o problema em tempo proporcional ao quadrado de r-p: basta ordenar o vetor v[p..r-1] sem dar atenção ao estado ordenado das duas metades. Mas isso é muito lento. Para obter um algoritmo mais rápido, será preciso usar uma área de trabalho, digamos w, do mesmo tipo e mesmo tamanho que o vetor v[p..r-1]. // A função recebe vetores crescentes v[p..q-1] // e v[q..r-1] e rearranja v[p..r-1] em ordem // crescente. void intercala1( int p, int q, int r, int v[]) { int i, j, k, *w; w = mallocc ( (r-p) * sizeof (int)); i = p; j = q; k = 0; while (i < q && j < r ) { if (v[i] <= v[j]) w[k++ ] = v[i++]; else w[k++] = v[j++]; } while (i < q) w[k++] = v[i++]; while (j < r) w[k++] = v[j++]; for (i = p; i < r; ++i) v[i] = w[i-p]; free( w) ; } Desempenho O tempo que a função consome para fazer o serviço é proporcional ao número de comparações entre elementos do vetor. Esse número é no máximo r - p - 1 . O

description

Nosso problema: Rearranjar um vetor v[0 .. n-1] de tal modo que ele fique em ordem crescente, ou seja, de tal modo que tenhamos v[0] ≤ . . . ≤ v[n-1]. Já analisamos alguns algoritmos simples para esse problema que consomem tempo proporcional a n2. Vamos examinar agora um algoritmo mais complexo mas bem mais rápido.

Transcript of Merge Sort

  • Mergesort: ordenao por intercalao

    Nosso problema: Rearranjar um vetor v[0 .. n-1] de tal modo que ele fique em

    ordem crescente, ou seja, de tal modo que tenhamos v[0] . . . v[n-1].

    J analisamos alguns algoritmos simples para esse problema que consomem tempo

    proporcional a n2. Vamos examinar agora um algoritmo mais complexo mas bem mais

    rpido.

    Intercalao de vetores ordenados

    Antes de resolver nosso problema principal preciso resolver o seguinte problema da

    intercalao (= merge): dados vetores crescentes v[p .. q-1] e v[q .. r-1],

    rearranjar v[p .. r-1] em ordem crescente.

    p q-1 q r-1

    111 333 555 555 777 999 999

    222 444 777 888

    fcil resolver o problema em tempo proporcional ao quadrado de r-p: basta ordenar

    o vetor v[p..r-1] sem dar ateno ao estado ordenado das duas metades. Mas isso

    muito lento.

    Para obter um algoritmo mais rpido, ser preciso usar uma rea de trabalho,

    digamos w, do mesmo tipo e mesmo tamanho que o vetor v[p..r-1].

    // A funo recebe vetores crescentes v[p..q-1]

    // e v[q..r-1] e rearranja v[p..r-1] em ordem

    // crescente.

    void

    intercala1( int p, int q, int r, int v[])

    {

    int i, j, k, *w;

    w = mallocc( (r-p) * sizeof (int));

    i = p; j = q;

    k = 0;

    while (i < q && j < r) {

    if (v[i]

  • consumo de tempo tambm proporcional ao nmero de movimentaes, ou seja,

    cpias de elementos do vetor de um lugar para outro. Esse nmero igual a 2(r-p).

    Resumindo, o consumo de tempo da funo

    proporcional a r - p ,

    ou seja, proporcional ao tamanho do vetor v[p..r-1].

    Exerccios 1

    1. A funo intercala1 est correta quando p igual a q, ou seja, quando o vetor

    v[p..q-1] est vazio? quando q igual a r, ou seja, quando o vetor v[q..r-1]

    est vazio?

    2. Analise e discuta a seguinte alternativa para a funo intercala1 (a alocao e liberao de memria foram omitidas):

    3. i = p; j = q; k = 0; 4. while (i < q && j < r) { 5. if (v[i] v[j]) w[k++] = v[j++]; 7. } 8. while (i < q) w[k++] = v[i++]; 9. while (j < r) w[k++] = v[j++]; 10. for (i = p; i < r; ++i) v[i] = w[i-p];

    11. Analise e discuta a seguinte alternativa para a funo intercala1 (a alocao e liberao de memria foram omitidas):

    12. i = p; j = q; k = 0; 13. while (i < q && j < r) { 14. if (v[i] = r || (i < q && v[i]

  • resultado da intercalao dos dois vetores dados. ( claro que z estar em ordem

    crescente.) Escreva duas verses da funo: uma iterativa e uma recursiva.

    38. Critique a funo de intercalao abaixo. (Observe que a funo faz a intercalao in loco, ou seja, no usa um vetor auxiliar.) Ela est correta? Quais

    os invariantes do while? Qual o consumo de tempo? 39. int i, k, t; 40. i = p; 41. while (i < q && q < r) { 42. if (v[i] >= v[q]) { 43. t = v[q]; 44. for (k = q - 1; k >= i; --k) 45. v[k+1] = v[k]; 46. v[i] = t; 47. ++q; 48. } 49. ++i; 50. }

    51. Um algoritmo de intercalao estvel se no altera a posio relativa de

    elementos iguais. A funo intercala1 discutida acima estvel? E se a

    comparao v[i]

  • Exerccios 2

    1. Critique a seguinte implementao da funo intercala2. (Suponha que MAX

    uma constante definida por um #define.) 2. int w[MAX], i, j, k; 3. for (i = p; i < q; ++i) w[i] = v[i]; 4. for (j = q; j < r; ++j) w[r+q-j-1] = v[j]; 5. i = p; j = r-1; 6. for (k = p; k < r; ++k) 7. if (w[i] < w[j]) v[k] = w[i++]; 8. else v[k] = w[j--];

    9. [Sedgewick 8.6] Mostre que a funo intercala2 discutida acima no estvel. Que modificaes preciso introduzir para que ela se torne estvel?

    Mergesort

    Agora podemos usar qualquer das funes intercala discutidas acima para escrever

    um algoritmo rpido de ordenao: o algoritmo recebe um vetor v[p..r-1] e rearranja

    o vetor em ordem crescente. O algoritmo recursivo. A base da recurso o caso p

    r-1; nesse caso, o vetor tem no mximo 1 elemento e portanto no preciso fazer nada.

    // A funo mergesort rearranja o vetor v[p..r-1]

    // em ordem crescente.

    void

    mergesort( int p, int r, int v[])

    {

    if (p < r-1) {

    int q = (p + r)/2;

    mergesort( p, q, v);

    mergesort( q, r, v);

    intercala( p, q, r, v);

    }

    }

    (O resultado da diviso por 2 na expresso (p+r)/2 automaticamente truncado. Por

    exemplo, (3+6)/2 vale 4.) Para rearranjar o vetor v[0..n-1] em ordem crescente

    basta executar mergesort( 0, n, v).

    0 1 2 3 4 5 6 7 8 9 10

    111 999 222 999 333 888 444 777 555 666 555

    111 999 222 999 333

    888 444 777 555 666 555

    111 999

    222 999 333

    888 444 777

    555 666 555

    .

    .

    .

    111 999

    222 333 999

    444 777 888

    555 555 666

    111 222 333 999 999

    444 555 555 666 777 88

    8

    111 222 333 444 555 555 666 777 888 999 999

  • Exerccios 3

    1. Considere a funo mergesort discutida acima. Que acontece se trocarmos

    (p+r)/2 por (p+r-1)/2? Que acontece se trocarmos (p+r)/2 por (p+r+1)/2?

    2. Submeta funo mergesort um vetor indexado por 1..4. Teremos a seguinte sequncia de invocaes da funo (observe a indentao):

    3. mergesort( 1,5,v) 4. mergesort( 1,3,v) 5. mergesort( 1,2,v) 6. mergesort( 2,3,v) 7. mergesort( 3,5,v) 8. mergesort( 3,4,v) 9. mergesort( 4,5,v)

    Repita o exerccio com um vetor indexado por 1..5.