Algoritmo de Ordenação por Intercalação
UnB-\(\gamma\)

Table of Contents

1. Algoritmos de Ordenação por Intercalação ( MergeSort )


1.1. MergeSort explicado de outra maneira


2. Discussão e Implementação

Discussão e implementação do Algoritmo linearítmico de Ordenação MergeSort.

Nesta aula foi discutido o algoritmo MergeSort, mas antes, iniciamos a discussão sobre o funcionamento da função intercala (merge) que é a base para o funcionamento do algoritmo de ordenação.

Na live foi implementada a intercalação que recebe dois ponteiros de vetores e seus respectivos intervalos fechados [l,r] (l para left [ou elemento mais a esquerda] e r para right [ou elemento mais a direita]) devolvendo um vetor alocado com os elementos dos dois vetores, a e b, intercalados. A função implementada em aula segue o conceito implementado abaixo:

 1: Item *intercala(Item *a, int la, int ra, Item *b, int lb, int rb)
 2: {
 3:   //Tamanhos dos vetores a e b
 4:   int ta=(ra-la+1);
 5:   int tb=(rb-lb+1);
 6: 
 7:   Item *c=malloc(sizeof(Item)*(ta+tb));
 8: 
 9:   //intervalos do vetor c
10:   int lc=0;
11:   int rc=(ta+tb-1);
12: 
13:   int ia=la, ib=lb,ic=lc;
14: 
15:   while(ia<=ra && ib<=rb)
16:   {
17:     if(lesseq(a[ia],b[ib]))
18:       c[ic++]=a[ia++];
19:     else
20:       c[ic++]=b[ib++];
21:   }
22:   while(ia<=ra)
23:     c[ic++]=a[ia++];
24:   while(ib<=rb)
25:     c[ic++]=b[ib++];
26:   return c;
27: }

Esta implementação difere, ligeiramente, da versão feita no vídeo indicado como MergeSort (no início da aula), que faz com que a função de intercalação receba um único vetor com os índices l,m,r (left,middle,right).

O efeito da intercalação é o mesmo, porém, a implementação feita em aula exige que o vetor c seja manipulado dentro do procedimento mergesort, diferentemente do outro vídeo.

A complexidade assintótica não é modificada e tão pouco agrega overhead adicional entre as versões. Fica interessante ter a manipulação diferente dos elementos para ter uma visão ampla da implementação.

Dessa forma o mergesort, em aula, foi implementado da seguinte forma:

28: void mergesort(Item *v,int l,int r)
29: {
30:   if(l>=r) return;
31:   int meio=(l+r)/2;
32:   mergesort(v,l,meio);
33:   mergesort(v,meio+1,r);
34:   //principal diferença do intercala não ser in-place
35:   Item *c=intercala(v,l,meio,v,meio+1,r);
36:   int t=r-l+1;
37:   for(int i=0;i<t;i++)
38:     v[l++]=c[i];
39:   free(c);
40: }

A principal diferença na mergesort acontece a partir da linha 35, onde o nosso procedimento manipula o vetor resultante da intercalação para dentro do vetor que está sendo ordenado.

Outra maneira de passar os parâmetros do vetor v como se fossem dois vetores realmente disjuntos, seria passando o ponteiro da posição inicial de cada left do vetor, substituindo a Linha 35 pela linha indicada abaixo:

1: Item *c=intercala(&v[l],0,meio-l,&v[meio+1],0,r-(meio+1));

O que acontece neste ponto é que passamos os ponteiros dos left de cada um dos vetores que devem ser intercalados, um deles começa em l e o outro em meio+1, o que precisamos calcular agora é qual seria o novo right de cada vetor, pois como cada vetor não começa no l do vetor original temos que recalcular o deslocamente de cada parte, ficando meio-l para a primeira metade e r-(meio+1) para a segunda metade.

  1. Material de apoio

3. Exercícios

3.1. Implemente o algoritmo da Intercalação (merge)

3.2. Implemente o algoritmo de ordenaçao por intercalação (mergesort)

3.3. Escreva uma função que

  • receba vetores disjuntos x[0..m-1] e y[0..n-1], ambos em ordem crescente, e produza um vetor z[0..m+n-1] que contenha o resultado da intercalação dos dois vetores dados.
    • É claro que z estará em ordem crescente.
  • Escreva duas versões da função: uma iterativa e uma recursiva.

3.4. Exercícios baseados do Professor Paulo Feofiloff

3.5. A respeito do problema da Intercalação (merge)

O problema da intercalação (merge) é clássico na computação e consiste em resolver o seguinte problema: dados vetores crescentes v[p .. q-1] e v[q .. r-1], rearranjar v[p .. r-1] em ordem crescente.

Uma leO é uma lista encadeada que contém uma sequência crescente de números inteiros. Escreva uma função que intercale duas leO dadas, produzindo assim uma terceira leO. Sua função não deve alocar novas células na memória, mas reaproveitar as células das duas listas dadas.

3.6. Execute o benchmark disponibilizado no Github

Faça o git clone do repositório https://github.com/bcribas/benchmark-ordenacao e siga as instruções do README para executar o experimento com algumas implementações.

Recomendo que neste momento você execute da seguinte maneira

TIMEOUT=3 BINARY="dummy bubblesort selectionsort insertionsortslow insertionsort mergesort" make time.reverso time.ordenado
  • Após a execução compare a diferença de execução entre os algoritmos e pondere suas implicações

3.7. Modifique a sua implementação do MergeSort para que ela mostre a quantidade de comparações feitas e compare com execuções feitas com os algoritmos elementares

3.8. O algoritmo MergeSort é estável?

3.9. Um algoritmo de intercalação é estável se não altera a posição relativa de elementos iguais. A função intercala é estável? E se a comparação lesseq(a[ia],b[ib]), for trocada por less(a[ia],b[ib])?

3.10. Implemente uma versão modificada do MergeSort com que ele considere os números ímpares sempre maiores que os números pares   HOT

  • Dessa maneira o vetor, sem ordenação, abaixo:

    30 44 1 93 44 77
    
  • Ficaria ordenado da seguinte maneira:

    30 44 44 1 77 93
    

Author: Bruno Ribas

Created: 2022-02-25 Fri 09:49

Validate