Open In App

3-way Merge Sort in Python

Merge sort involves recursively splitting the array into 2 parts, sorting, and finally merging them. A variant of merge sort is called 3-way merge sort where instead of splitting the array into 2 parts we split it into 3 parts

Examples:

Input: arr = [12, 11, 13, 5, 6, 7]
Output: [5, 6, 7, 11, 12, 13]

Input: arr = [38, 27, 43, 3, 9, 82, 10]
Output: [3, 9, 10, 27, 38, 43, 82]

Approach:

Merge sort recursively breaks down the arrays to subarrays of size half. Similarly, 3-way Merge sort breaks down the arrays to subarrays of size one third. 

Step-by-step algorithm:

  1. Divide the unsorted list into three sublists.
  2. Recursively sort each sublist.
  3. Merge the three sorted sublists to produce the final sorted list.

Below is the implementation of the above idea:

# Python Program to perform 3 way Merge Sort

""" Merge the sorted ranges [low, mid1), [mid1,mid2) 
and [mid2, high) mid1 is first midpoint 
index in overall range to merge mid2 is second 
midpoint index in overall range to merge"""


def merge(gArray, low, mid1, mid2, high, destArray):
    i = low
    j = mid1
    k = mid2
    l = low

    # Choose smaller of the smallest in the three ranges
    while ((i < mid1) and (j < mid2) and (k < high)):
        if(gArray[i] < gArray[j]):
            if(gArray[i] < gArray[k]):
                destArray[l] = gArray[i]
                l += 1
                i += 1
            else:
                destArray[l] = gArray[k]
                l += 1
                k += 1
        else:
            if(gArray[j] < gArray[k]):
                destArray[l] = gArray[j]
                l += 1
                j += 1
            else:
                destArray[l] = gArray[k]
                l += 1
                k += 1

    # Case where first and second ranges
    # have remaining values
    while ((i < mid1) and (j < mid2)):
        if(gArray[i] < gArray[j]):
            destArray[l] = gArray[i]
            l += 1
            i += 1
        else:
            destArray[l] = gArray[j]
            l += 1
            j += 1

    # case where second and third ranges
    # have remaining values
    while ((j < mid2) and (k < high)):
        if(gArray[j] < gArray[k]):
            destArray[l] = gArray[j]
            l += 1
            j += 1
        else:
            destArray[l] = gArray[k]
            l += 1
            k += 1

    # Case where first and third ranges have
    # remaining values
    while ((i < mid1) and (k < high)):
        if(gArray[i] < gArray[k]):
            destArray[l] = gArray[i]
            l += 1
            i += 1
        else:
            destArray[l] = gArray[k]
            l += 1
            k += 1

    # Copy remaining values from the first range
    while (i < mid1):
        destArray[l] = gArray[i]
        l += 1
        i += 1

    # Copy remaining values from the second range
    while (j < mid2):
        destArray[l] = gArray[j]
        l += 1
        j += 1

    # Copy remaining values from the third range
    while (k < high):
        destArray[l] = gArray[k]
        l += 1
        k += 1


""" Performing the merge sort algorithm on the 
given array of values in the rangeof indices 
[low, high). low is minimum index, high is 
maximum index (exclusive) """


def mergeSort3WayRec(gArray, low, high, destArray):
    # If array size is 1 then do nothing
    if (high - low < 2):
        return

    # Splitting array into 3 parts
    mid1 = low + ((high - low) // 3)
    mid2 = low + 2 * ((high - low) // 3) + 1

    # Sorting 3 arrays recursively
    mergeSort3WayRec(destArray, low, mid1, gArray)
    mergeSort3WayRec(destArray, mid1, mid2, gArray)
    mergeSort3WayRec(destArray, mid2, high, gArray)

    # Merging the sorted arrays
    merge(destArray, low, mid1, mid2, high, gArray)


def mergeSort3Way(gArray, n):
    # if array size is zero return null
    if (n == 0):
        return

    # creating duplicate of given array
    fArray = []

    # copying elements of given array into
    # duplicate array
    fArray = gArray.copy()

    # sort function
    mergeSort3WayRec(fArray, 0, n, gArray)

    # copy back elements of duplicate array
    # to given array
    gArray = fArray.copy()

    # return the sorted array
    return gArray


data = [45, -2, -45, 78, 30, -42, 10, 19, 73, 93]
data = mergeSort3Way(data, 10)
print("After 3 way merge sort: ", end="")
for i in range(10):
    print(f"{data[i]} ", end="")

Output
After 3 way merge sort: -45 -42 -2 10 19 30 45 73 78 93 

Time Complexity: O(n log n)
Auxiliary Space: O(n)

Advantages of 3-way Merge Sort:

  1. Efficiency: 3-way merge sort can be more efficient than traditional merge sort, especially when dealing with large datasets or arrays with many duplicate elements.
  2. Reduced Number of Comparisons: By merging three sorted sub-arrays instead of two, the number of comparisons needed during merging is reduced, leading to potentially faster sorting.
  3. Improved Performance: In certain scenarios, 3-way merge sort can outperform traditional merge sort, resulting in better overall performance.
  4. Stable Sorting: Like traditional merge sort, 3-way merge sort is stable, meaning it preserves the relative order of equal elements in the sorted array.

Disadvantages of 3-way Merge Sort:

  1. Extra Overhead: Implementing and managing the merging of three sub-arrays instead of two can introduce additional complexity and overhead, potentially impacting performance.
  2. Increased Memory Usage: 3-way merge sort may require more memory compared to traditional merge sort due to the need to merge three sub-arrays instead of two, especially for larger datasets.
  3. Limited Impact: The benefits of 3-way merge sort may not always be significant, particularly for small or already partially sorted arrays, where the overhead of managing three sub-arrays may outweigh any potential performance gains.
Article Tags :