How to implement a Recursive Merge

2

I have a MergeSort algorithm and would like to implement the merge function recursively, not the recursive MergeSort but the Merge function of it. Here is the Merge Function and Merge Sort code:

void mergeInt (int v[], int inicio, int fim)
{
  int meio = (inicio + fim) / 2;
  int i = inicio;       
  int j = meio + 1;     

  int tam = fim - inicio + 1;
  int *aux = malloc (sizeof (int) * tam);   

  int k = 0;
  while (i <= meio || j <= fim)
    {
      if (i > meio)
    {           
      aux[k] = v[j];
      j++;
    }
      else if (j > fim)
    {           
      aux[k] = v[i];
      i++;
    }
      else if (v[i] < v[j])
    {           
      aux[k] = v[i];
      i++;
    }
      else
    {           
      aux[k] = v[j];
      j++;
    }

      k++;
    }

  int l;
  for (l = 0; l < tam; l++)
    {
      v[inicio + l] = aux[l];
    }

  free (aux);
}

void mergeSortInt(int v[], int inicio, int fim)
{
  int meio = (inicio + fim) / 2;

  if (inicio < fim)
    {
      mergeSortInt (v, inicio, meio);
      mergeSortInt (v, meio + 1, fim);

      mergeInt (v, inicio, fim);
    }
}
    
asked by anonymous 21.07.2018 / 19:39

1 answer

1

First, I ran a test for your code:

void mergeSort(int v[], int tamanho) {
    mergeSortInt(v, 0, tamanho);
}

int main() {
    int a[] = {10, 2, 7, 1, 4, 9, 3, 8, 0, 5, 6};
    mergeSort(a, 11);
    for (int i = 0; i < 11; i++) {
        printf("%d ", a[i]);
    }
}

See it working here.

Before turning the mergeInt from iterative to recursive, you need to make some changes to resolve some things that would prevent the recursive version from working:

  • Attack your malloc and free . Even in the iterative version, using a lot of malloc s and free s is somewhat inefficient, it would be better to use only one in the entire mergesort process.

  • We remove from the mergeInt , the last for that copies from aux to v .

  • Within while , we change the if to have only two possible paths instead of four.

The code looks like this:

void mergeInt(int v[], int inicio, int fim, int aux[]) {
    int meio = (inicio + fim) / 2;
    int i = inicio;
    int j = meio + 1;
    int k = 0;
    while (i <= meio || j <= fim) {
        if (i <= meio && (j > fim || v[i] < v[j])) {
            aux[k] = v[i];
            i++;
        } else {
            aux[k] = v[j];
            j++;
        }
        k++;
    }
}

void mergeSortInt(int v[], int inicio, int fim, int aux[]) {
    int meio = (inicio + fim) / 2;

    if (inicio < fim) {
        mergeSortInt(v, inicio, meio, aux);
        mergeSortInt(v, meio + 1, fim, aux);
        mergeInt(v, inicio, fim, aux);

        for (int l = 0; l < fim - inicio + 1; l++) {
            v[inicio + l] = aux[l];
        }
    }
}

void mergeSort(int v[], int tamanho) {
    int *aux = malloc(sizeof(int) * tamanho);
    mergeSortInt(v, 0, tamanho, aux);
    free(aux);
}

int main() {
    int a[] = {10, 2, 7, 1, 4, 9, 3, 8, 0, 5, 6};
    mergeSort(a, 11);
    for (int i = 0; i < 11; i++) {
        printf("%d ", a[i]);
    }
}

See here working on ideone.

At this point, note that the mergeInt function has been reduced to being little more than just a while loop. That way, we can now make it recursive.

The parameters inicio and fim are exchanged for i , meio , j and fim . The logic is that i and meio correspond to one of the ranges that will be merged into aux and j and fim corresponds to the other range. The k also becomes a parameter to indicate at which point of aux the interleaving between the two ranges is happening.

The code looks like this:

void mergeInt(int v[], int i, int meio, int j, int fim, int k, int aux[]) {
    if (i <= meio && (j > fim || v[i] < v[j])) {
        aux[k] = v[i];
        mergeInt(v, i + 1, meio, j, fim, k + 1, aux);
    } else if (j <= fim) {
        aux[k] = v[j];
        mergeInt(v, i, meio, j + 1, fim, k + 1, aux);
    }
}

void mergeSortInt(int v[], int inicio, int fim, int aux[]) {
    int meio = (inicio + fim) / 2;

    if (inicio < fim) {
        mergeSortInt(v, inicio, meio, aux);
        mergeSortInt(v, meio + 1, fim, aux);
        mergeInt(v, inicio, meio, meio + 1, fim, 0, aux);

        for (int l = 0; l < fim - inicio + 1; l++) {
            v[inicio + l] = aux[l];
        }
    }
}

void mergeSort(int v[], int tamanho) {
    int *aux = malloc(sizeof(int) * tamanho);
    mergeSortInt(v, 0, tamanho, aux);
    free(aux);
}

int main() {
    int a[] = {10, 2, 7, 1, 4, 9, 3, 8, 0, 5, 6};
    mergeSort(a, 11);
    for (int i = 0; i < 11; i++) {
        printf("%d ", a[i]);
    }
}

See here working on ideone.

    
21.07.2018 / 20:33