2

Does this mergeSort algorithm use mutual recursion? I realize that mergeSort calls the merge function and it calls itself (mergeSort), but since merge does not call mergeSort is it not mutual recursion and simply just recursion?

function mergeSort(arr) {
    // split array
    ...
    return merge(mergSort(firstHalf), mergeSort(secondHalf));
}

function merge (array1, array2) {
    // merge both arrays
    ...
    return singleArray;
}
georgej
  • 3,041
  • 6
  • 24
  • 46

2 Answers2

2

Correct: this is simple recursion. Mutual recursion is also called indirect recursion: A calls B; B calls A.

Your analysis is exactly correct: were merge to call mergeSort, then you would have mutual recursion. In the posted code, the call to merge is a simple parent-child link on the call tree.

Prune
  • 76,765
  • 14
  • 60
  • 81
1

To follow up with an explanation about mutual recursion for merge sort, it is one of the methods used to optimize top down merge sort to avoid a copy step during the merge, where the direction of the merging depends on the level of recursion. The alternative to this is to pass a flag as a parameter for the direction to merge. In the example code below, a[] is the original array, b[] is the working array. TopDownSplitMergeAtoA returns with sorted data in the original array, and TopDownSplitMergeAtoB returns with sorted data in the working array, with TopDownSplitMergeAtoA calling TopDownSplitMergeAtoB and vice versa (this is the mutual recursion). The only copy operation occurs if the sub-array size is one for TopDownSplitMergeAtoB, in which case one element is copied from the original array to the working array.

void TopDownSplitMergeAtoA(int a[], int b[], size_t ll, size_t ee);
void TopDownSplitMergeAtoB(int a[], int b[], size_t ll, size_t ee);
void Merge(int a[], int b[], size_t ll, size_t rr, size_t ee);

void MergeSort(int a[], size_t n)       // entry function
{
    if(n < 2)                           // if size < 2 return
        return;
    int *b = new int[n];
    TopDownSplitMergeAtoA(a, b, 0, n);
    delete[] b;
}

void TopDownSplitMergeAtoA(int a[], int b[], size_t ll, size_t ee)
{
    if((ee - ll) == 1)                  // if size == 1 return
        return;
    size_t rr = (ll + ee)>>1;           // midpoint, start of right half
    TopDownSplitMergeAtoB(a, b, ll, rr);
    TopDownSplitMergeAtoB(a, b, rr, ee);
    Merge(b, a, ll, rr, ee);     // merge b to a
}

void TopDownSplitMergeAtoB(int a[], int b[], size_t ll, size_t ee)
{
    if((ee - ll) == 1){                 // if size == 1 copy a to b
        b[ll] = a[ll];
        return;
    }
    size_t rr = (ll + ee)>>1;           // midpoint, start of right half
    TopDownSplitMergeAtoA(a, b, ll, rr);
    TopDownSplitMergeAtoA(a, b, rr, ee);
    Merge(a, b, ll, rr, ee);     // merge a to b
}

void Merge(int a[], int b[], size_t ll, size_t rr, size_t ee)
{
    size_t o = ll;                      // b[]       index
    size_t l = ll;                      // a[] left  index
    size_t r = rr;                      // a[] right index
    while(1){                           // merge data
        if(a[l] <= a[r]){               // if a[l] <= a[r]
            b[o++] = a[l++];            //   copy a[l]
            if(l < rr)                  //   if not end of left run
                continue;               //     continue (back to while)
            while(r < ee)               //   else copy rest of right run
                b[o++] = a[r++];
            break;                      //     and return
        } else {                        // else a[l] > a[r]
            b[o++] = a[r++];            //   copy a[r]
            if(r < ee)                  //   if not end of right run
                continue;               //     continue (back to while)
            while(l < rr)               //   else copy rest of left run
                b[o++] = a[l++];
            break;                      //     and return
        }
    }
}
rcgldr
  • 27,407
  • 3
  • 36
  • 61