3-way Merge Sort
Merge Sort is a divide-and-conquer algorithm that recursively splits an array into two halves, sorts each half, and then merges them. A variation of this is 3-way Merge Sort, where instead of splitting the array into two parts, we divide it into three equal parts.
In traditional Merge Sort, the array is recursively divided into halves until we reach subarrays of size 1. In 3-way Merge Sort, the array is recursively divided into three parts, reducing the depth of recursion and potentially improving efficiency.
Examples:
Input: arr = [45, -2, -45, 78, 30, -42, 10, 19, 73, 93]
Output: [-45, -42, -2, 10, 19, 30, 45, 73, 78, 93]Input: arr = [23, -19]
Output: [-19, 23]
Approach:
The idea is to extend merge sort by dividing the array into three parts instead of two. First, recursively sort the three subarrays. Then, merge them by selecting the smallest element among the three at each step. Temporary arrays store the divided parts, and a comparison process finds the minimum to insert into the original array.
Steps to implement the above idea:
- Divide the array into three equal parts using two midpoints.
- Recursively sort each of the three subarrays.
- Create temporary arrays to store the three divided parts.
- Use three pointers to track positions in the three subarrays.
- Find the minimum element among the three at each step.
- Merge the sorted subarrays back into the original array.
- Repeat the process until the entire array is sorted.
// C++ program to implement 3-way Merge Sort
#include <bits/stdc++.h>
using namespace std;
void merge(int arr[], int left, int mid1, int mid2, int right) {
// Sizes of three subarrays
int size1 = mid1 - left + 1;
int size2 = mid2 - mid1;
int size3 = right - mid2;
// Temporary arrays for three parts
vector<int> leftArr(size1), midArr(size2), rightArr(size3);
// Copy data to temporary arrays
for (int i = 0; i < size1; i++) {
leftArr[i] = arr[left + i];
}
for (int i = 0; i < size2; i++) {
midArr[i] = arr[mid1 + 1 + i];
}
for (int i = 0; i < size3; i++) {
rightArr[i] = arr[mid2 + 1 + i];
}
// Merge three sorted subarrays
int i = 0, j = 0, k = 0, index = left;
while (i < size1 || j < size2 || k < size3) {
int minValue = INT_MAX, minIdx = -1;
// Find the smallest among the three current elements
if (i < size1 && leftArr[i] < minValue) {
minValue = leftArr[i];
minIdx = 0;
}
if (j < size2 && midArr[j] < minValue) {
minValue = midArr[j];
minIdx = 1;
}
if (k < size3 && rightArr[k] < minValue) {
minValue = rightArr[k];
minIdx = 2;
}
// Place the smallest element in the merged array
if (minIdx == 0) {
arr[index++] = leftArr[i++];
} else if (minIdx == 1) {
arr[index++] = midArr[j++];
} else {
arr[index++] = rightArr[k++];
}
}
}
void threeWayMergeSort(int arr[], int left, int right) {
// Base case: If single element, return
if (left >= right) {
return;
}
// Finding two midpoints for 3-way split
int mid1 = left + (right - left) / 3;
int mid2 = left + 2 * (right - left) / 3;
// Recursively sort first third
threeWayMergeSort(arr, left, mid1);
// Recursively sort second third
threeWayMergeSort(arr, mid1 + 1, mid2);
// Recursively sort last third
threeWayMergeSort(arr, mid2 + 1, right);
// Merge the sorted parts
merge(arr, left, mid1, mid2, right);
}
int main() {
// Input array
int arr[] = {5, 2, 9, 1, 6, 3, 8, 4, 7};
// Size of the array
int n = sizeof(arr) / sizeof(arr[0]);
// Calling 3-way merge sort function
threeWayMergeSort(arr, 0, n - 1);
// Printing the sorted array
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
return 0;
}
// C program to implement 3-way Merge Sort
#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
void merge(int arr[], int left, int mid1, int mid2, int right) {
// Sizes of three subarrays
int size1 = mid1 - left + 1;
int size2 = mid2 - mid1;
int size3 = right - mid2;
// Temporary arrays for three parts
int *leftArr = (int *)malloc(size1 * sizeof(int));
int *midArr = (int *)malloc(size2 * sizeof(int));
int *rightArr = (int *)malloc(size3 * sizeof(int));
// Copy data to temporary arrays
for (int i = 0; i < size1; i++) {
leftArr[i] = arr[left + i];
}
for (int i = 0; i < size2; i++) {
midArr[i] = arr[mid1 + 1 + i];
}
for (int i = 0; i < size3; i++) {
rightArr[i] = arr[mid2 + 1 + i];
}
// Merge three sorted subarrays
int i = 0, j = 0, k = 0, index = left;
while (i < size1 || j < size2 || k < size3) {
int minValue = INT_MAX, minIdx = -1;
// Find the smallest among the three current elements
if (i < size1 && leftArr[i] < minValue) {
minValue = leftArr[i];
minIdx = 0;
}
if (j < size2 && midArr[j] < minValue) {
minValue = midArr[j];
minIdx = 1;
}
if (k < size3 && rightArr[k] < minValue) {
minValue = rightArr[k];
minIdx = 2;
}
// Place the smallest element in the merged array
if (minIdx == 0) {
arr[index++] = leftArr[i++];
} else if (minIdx == 1) {
arr[index++] = midArr[j++];
} else {
arr[index++] = rightArr[k++];
}
}
free(leftArr);
free(midArr);
free(rightArr);
}
void threeWayMergeSort(int arr[], int left, int right) {
// Base case: If single element, return
if (left >= right) {
return;
}
// Finding two midpoints for 3-way split
int mid1 = left + (right - left) / 3;
int mid2 = left + 2 * (right - left) / 3;
// Recursively sort first third
threeWayMergeSort(arr, left, mid1);
// Recursively sort second third
threeWayMergeSort(arr, mid1 + 1, mid2);
// Recursively sort last third
threeWayMergeSort(arr, mid2 + 1, right);
// Merge the sorted parts
merge(arr, left, mid1, mid2, right);
}
int main() {
// Input array
int arr[] = {5, 2, 9, 1, 6, 3, 8, 4, 7};
// Size of the array
int n = sizeof(arr) / sizeof(arr[0]);
// Calling 3-way merge sort function
threeWayMergeSort(arr, 0, n - 1);
// Printing the sorted array
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
return 0;
}
// Java program to implement 3-way Merge Sort
import java.util.*;
class GfG {
static void merge(int arr[], int left, int mid1, int mid2, int right) {
// Sizes of three subarrays
int size1 = mid1 - left + 1;
int size2 = mid2 - mid1;
int size3 = right - mid2;
// Temporary arrays for three parts
int[] leftArr = new int[size1];
int[] midArr = new int[size2];
int[] rightArr = new int[size3];
// Copy data to temporary arrays
for (int i = 0; i < size1; i++) {
leftArr[i] = arr[left + i];
}
for (int i = 0; i < size2; i++) {
midArr[i] = arr[mid1 + 1 + i];
}
for (int i = 0; i < size3; i++) {
rightArr[i] = arr[mid2 + 1 + i];
}
// Merge three sorted subarrays
int i = 0, j = 0, k = 0, index = left;
while (i < size1 || j < size2 || k < size3) {
int minValue = Integer.MAX_VALUE, minIdx = -1;
// Find the smallest among the three current elements
if (i < size1 && leftArr[i] < minValue) {
minValue = leftArr[i];
minIdx = 0;
}
if (j < size2 && midArr[j] < minValue) {
minValue = midArr[j];
minIdx = 1;
}
if (k < size3 && rightArr[k] < minValue) {
minValue = rightArr[k];
minIdx = 2;
}
// Place the smallest element in the merged array
if (minIdx == 0) {
arr[index++] = leftArr[i++];
} else if (minIdx == 1) {
arr[index++] = midArr[j++];
} else {
arr[index++] = rightArr[k++];
}
}
}
static void threeWayMergeSort(int arr[], int left, int right) {
// Base case: If single element, return
if (left >= right) {
return;
}
// Finding two midpoints for 3-way split
int mid1 = left + (right - left) / 3;
int mid2 = left + 2 * (right - left) / 3;
// Recursively sort first third
threeWayMergeSort(arr, left, mid1);
// Recursively sort second third
threeWayMergeSort(arr, mid1 + 1, mid2);
// Recursively sort last third
threeWayMergeSort(arr, mid2 + 1, right);
// Merge the sorted parts
merge(arr, left, mid1, mid2, right);
}
public static void main(String args[]) {
// Input array
int arr[] = {5, 2, 9, 1, 6, 3, 8, 4, 7};
// Size of the array
int n = arr.length;
// Calling 3-way merge sort function
threeWayMergeSort(arr, 0, n - 1);
// Printing the sorted array
for (int i = 0; i < n; i++) {
System.out.print(arr[i] + " ");
}
}
}
# Python program to implement 3-way Merge Sort
def merge(arr, left, mid1, mid2, right):
# Sizes of three subarrays
size1 = mid1 - left + 1
size2 = mid2 - mid1
size3 = right - mid2
# Temporary arrays for three parts
left_arr = arr[left:left + size1]
mid_arr = arr[mid1 + 1:mid1 + 1 + size2]
right_arr = arr[mid2 + 1:mid2 + 1 + size3]
# Merge three sorted subarrays
i = j = k = 0
index = left
while i < size1 or j < size2 or k < size3:
min_value = float('inf')
min_idx = -1
# Find the smallest among the three current elements
if i < size1 and left_arr[i] < min_value:
min_value = left_arr[i]
min_idx = 0
if j < size2 and mid_arr[j] < min_value:
min_value = mid_arr[j]
min_idx = 1
if k < size3 and right_arr[k] < min_value:
min_value = right_arr[k]
min_idx = 2
# Place the smallest element in the merged array
if min_idx == 0:
arr[index] = left_arr[i]
i += 1
elif min_idx == 1:
arr[index] = mid_arr[j]
j += 1
else:
arr[index] = right_arr[k]
k += 1
index += 1
def three_way_merge_sort(arr, left, right):
# Base case: If single element, return
if left >= right:
return
# Finding two midpoints for 3-way split
mid1 = left + (right - left) // 3
mid2 = left + 2 * (right - left) // 3
# Recursively sort first third
three_way_merge_sort(arr, left, mid1)
# Recursively sort second third
three_way_merge_sort(arr, mid1 + 1, mid2)
# Recursively sort last third
three_way_merge_sort(arr, mid2 + 1, right)
# Merge the sorted parts
merge(arr, left, mid1, mid2, right)
if __name__ == "__main__":
# Input array
arr = [5, 2, 9, 1, 6, 3, 8, 4, 7]
# Calling 3-way merge sort function
three_way_merge_sort(arr, 0, len(arr) - 1)
# Printing the sorted array
print(*arr)
// C# program to implement 3-way Merge Sort
using System;
class GfG {
// Function to merge three sorted subarrays
static void Merge(int[] arr, int left, int mid1, int mid2, int right) {
// Sizes of three subarrays
int size1 = mid1 - left + 1;
int size2 = mid2 - mid1;
int size3 = right - mid2;
// Temporary arrays for three parts
int[] leftArr = new int[size1];
int[] midArr = new int[size2];
int[] rightArr = new int[size3];
// Copy data to temporary arrays
for (int i = 0; i < size1; i++) {
leftArr[i] = arr[left + i];
}
for (int i = 0; i < size2; i++) {
midArr[i] = arr[mid1 + 1 + i];
}
for (int i = 0; i < size3; i++) {
rightArr[i] = arr[mid2 + 1 + i];
}
// Merge three sorted subarrays
int i1 = 0, i2 = 0, i3 = 0, index = left;
while (i1 < size1 || i2 < size2 || i3 < size3) {
int minValue = int.MaxValue, minIdx = -1;
// Find the smallest among the three current elements
if (i1 < size1 && leftArr[i1] < minValue) {
minValue = leftArr[i1];
minIdx = 0;
}
if (i2 < size2 && midArr[i2] < minValue) {
minValue = midArr[i2];
minIdx = 1;
}
if (i3 < size3 && rightArr[i3] < minValue) {
minValue = rightArr[i3];
minIdx = 2;
}
// Place the smallest element in the merged array
if (minIdx == 0) {
arr[index++] = leftArr[i1++];
} else if (minIdx == 1) {
arr[index++] = midArr[i2++];
} else {
arr[index++] = rightArr[i3++];
}
}
}
// Function to perform 3-way merge sort
static void ThreeWayMergeSort(int[] arr, int left, int right) {
// Base case: If single element, return
if (left >= right) {
return;
}
// Finding two midpoints for 3-way split
int mid1 = left + (right - left) / 3;
int mid2 = left + 2 * (right - left) / 3;
// Recursively sort first third
ThreeWayMergeSort(arr, left, mid1);
// Recursively sort second third
ThreeWayMergeSort(arr, mid1 + 1, mid2);
// Recursively sort last third
ThreeWayMergeSort(arr, mid2 + 1, right);
// Merge the sorted parts
Merge(arr, left, mid1, mid2, right);
}
// Driver method
public static void Main() {
// Input array
int[] arr = {5, 2, 9, 1, 6, 3, 8, 4, 7};
// Size of the array
int n = arr.Length;
// Calling 3-way merge sort function
ThreeWayMergeSort(arr, 0, n - 1);
// Printing the sorted array
foreach (int num in arr) {
Console.Write(num + " ");
}
}
}
// Javascript program to implement 3-way Merge Sort
function merge(arr, left, mid1, mid2, right) {
// Sizes of three subarrays
let size1 = mid1 - left + 1;
let size2 = mid2 - mid1;
let size3 = right - mid2;
// Temporary arrays for three parts
let leftArr = arr.slice(left, left + size1);
let midArr = arr.slice(mid1 + 1, mid1 + 1 + size2);
let rightArr = arr.slice(mid2 + 1, mid2 + 1 + size3);
// Merge three sorted subarrays
let i = 0, j = 0, k = 0, index = left;
while (i < size1 || j < size2 || k < size3) {
let minValue = Infinity;
let minIdx = -1;
// Find the smallest among the three current elements
if (i < size1 && leftArr[i] < minValue) {
minValue = leftArr[i];
minIdx = 0;
}
if (j < size2 && midArr[j] < minValue) {
minValue = midArr[j];
minIdx = 1;
}
if (k < size3 && rightArr[k] < minValue) {
minValue = rightArr[k];
minIdx = 2;
}
// Place the smallest element in the merged array
if (minIdx === 0) {
arr[index] = leftArr[i++];
} else if (minIdx === 1) {
arr[index] = midArr[j++];
} else {
arr[index] = rightArr[k++];
}
index++;
}
}
function threeWayMergeSort(arr, left, right) {
// Base case: If single element, return
if (left >= right) {
return;
}
// Finding two midpoints for 3-way split
let mid1 = left + Math.floor((right - left) / 3);
let mid2 = left + 2 * Math.floor((right - left) / 3);
// Recursively sort first third
threeWayMergeSort(arr, left, mid1);
// Recursively sort second third
threeWayMergeSort(arr, mid1 + 1, mid2);
// Recursively sort last third
threeWayMergeSort(arr, mid2 + 1, right);
// Merge the sorted parts
merge(arr, left, mid1, mid2, right);
}
// Input array
let arr = [5, 2, 9, 1, 6, 3, 8, 4, 7];
// Calling 3-way merge sort function
threeWayMergeSort(arr, 0, arr.length - 1);
// Printing the sorted array
console.log(...arr);
Output
1 2 3 4 5 6 7 8 9
Time Complexity: O(n log₃ n), because the array is divided into three parts at each level, and merging takes O(n) time per level, leading to a recurrence of T(n) = 3T(n/3) + O(n).
Auxiliary Space: O(n) due to the use of temporary arrays for storing the three subarrays during merging.
Similar article: 3 way Quick Sort