How can I convert pseudocode to mergesort algorithm?

Question:

I need to convert pseudocode into a merge sort algorithm that mirrors that pseudocode. I am new to pseudocode so I’m having trouble with this. Can anyone tell me what is wrong with my algorithm? Please note that the arrays in the pseudocode are 1-indexed.

PSEUDOCODE:

MergeSort(A[1 .. n]):
   if n > 1
      m ← bn/2c
      MergeSort(A[1 .. m])
      MergeSort(A[m + 1 .. n])
      Merge(A[1 .. n], m)

Merge(A[1 .. n], m):
   i ← 1; j ← m + 1
   for k ← 1 to n
      if j > n
         B[k] ← A[i]; i ← i + 1
      else if i > m
         B[k] ← A[j]; j ← j + 1
      else if A[i] < A[ j]
         B[k] ← A[i]; i ← i + 1
      else
         B[k] ← A[j]; j ← j + 1
   for k ← 1 to n
      A[k] ← B[k]

MY CODE

def mergeSort(arr):
    n = len(arr)
    if n > 1:
        m = n//2
        mergeSort(arr[:m])
        mergeSort(arr[m:])
        merge(arr, m)

def merge(arr, m):
    n = len(arr)
    i = 0
    j = m
    b = [0] * n
    
    for k in range(n):
        if j >= n:
            b[k] = arr[i]
            i += 1
        elif i > m-1:
            b[k] = arr[j]
            j += 1
        elif arr[i] < arr[j]:
            b[k] = arr[i]
            i += 1
        else:
            b[k] = arr[j]
            j += 1
    for k in range(n):
        arr[k] = b[k] 
Asked By: jope

||

Answers:

This code is working fine for me, however your operations are being applied in place, so you just need to call the function with the array to sort rather than getting the return value (which will always be None, because you provide no return in the function mergeSort)

arr = np.random.uniform(1, 10, 10)
print(arr)

[2.10748505 9.47408117 5.4620788  1.5585025  9.57387679 4.13719947
 1.28671255 4.150946   2.84044402 6.56294717]

mergeSort(arr)
print(arr)

[1.28671255 1.5585025  2.10748505 2.84044402 4.13719947 4.150946
 5.4620788  6.56294717 9.47408117 9.57387679]
Answered By: Tom McLean

The thing is that in the pseudo code version, the notation A[1..m] is supposed to mean a partition of the array, but in-place, not as a new array (slice): it is like a window on a part of the array, with its own indexing, but not copied.

The translation to list slicing in Python does not reflect this. arr[:m] creates a new list, and so whatever mergeSort(arr[:m]) does with that new list, it doesn’t touch arr itself: all that work is for nothing, as it doesn’t mutate arr, but a sliced copy of it, which we lose access to.

A solution is to not create slices, but to pass the start/end indices of the intended partition to the function call.

Here is the adapted code:

def mergeSort(arr):
    mergeSortRec(arr, 0, len(arr))

def mergeSortRec(arr, start, end):
    n = end - start
    if n > 1:
        m = start + n//2
        mergeSortRec(arr, start, m)
        mergeSortRec(arr, m, end)
        merge(arr, start, m, end)

def merge(arr, start, m, end):
    n = end - start
    i = start
    j = m
    b = [0] * n
    
    for k in range(n):
        if j >= end:
            b[k] = arr[i]
            i += 1
        elif i >= m:
            b[k] = arr[j]
            j += 1
        elif arr[i] < arr[j]:
            b[k] = arr[i]
            i += 1
        else:
            b[k] = arr[j]
            j += 1
    for k in range(n):
        arr[start + k] = b[k] 
Answered By: trincot