Merge K sorted arrays | Set 3 ( Using Divide and Conquer Approach )

Giving k sorted arrays, each of size N, the task is to merge them into a single sorted array.

Examples:

Input : arr[][] = {{5, 7, 15, 18},
                   {1, 8, 9, 17},
                   {1, 4, 7, 7}}
Output :  {1, 1, 4, 5, 7, 7, 7, 8, 9, 15, 17, 18}

Input : arr[][] = {{3, 2, 1}
                   {6, 5, 4}}
Output :  {1, 2, 3, 4, 5, 6}

Prerequisite: Merge Sort

Simple Solution: A simple solution is to append all the arrays one after another and sort them. The time complexity of this operation will be O(N*k * log(N*k)).

Efficient Solution: The idea becomes clear once we start looking at the k arrays as the intermediate state of merge sort algorithm.

Since, we have got k arrays that are already sorted, all we need to do is merge the k arrays. Merging them, will create a recursion tree of log(k) height because, at each step, the number of remaining arrays becomes half. At each height, the algorithm will take a time of O(N*k). Thus, the time complexity boils down to O( N*k * log(k) ).

Algorithm:

  1. Initialize the output array with the size N*k.
  2. Call the function divide. Let l and r represent the range of arrays that are to be merged and thus vary between 0 to k-1.
  3. At each step, we call the left and right half of the range recursively so that, they will be sorted and stored in the output array.
  4. After that, we merge the left and right half. For merging, we need to determine the range of indexes for the left and right halves in the output array. We can easily find that.
    • Left part will start from the index l * n of the output array.
    • Similarly, right part will start from the index ((l + r) / 2 + 1) * n of the output array.

We, also have to determine the length of the left and right parts.
Then, we create two temporary arrays, ‘l_arr’ and ‘r_arr’ to store the values from the left and right part. Finally, we use two pointer technique to merge the results of the left and right part as we do in merge sort.

Below is the implementation of the above algorithm:

C++

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ program to merge K sorted arrays
  
#include <iostream>
#define n 4
  
using namespace std;
  
// Function to perform merge operation
void merge(int l, int r, int* output)
{
    // to store the starting point of left
    // and right array
    int l_in = l * n, r_in = ((l + r) / 2 + 1) * n;
  
    // to store the size of left and
    // right array
    int l_c = ((l + r) / 2 - l + 1) * n;
    int r_c = (r - (l + r) / 2) * n;
  
    // array to temporarily store left
    // and right array
    int l_arr[l_c], r_arr[r_c];
  
    // storing data in left array
    for (int i = 0; i < l_c; i++)
        l_arr[i] = output[l_in + i];
  
    // storing data in right array
    for (int i = 0; i < r_c; i++)
        r_arr[i] = output[r_in + i];
  
    // to store the current index of
    // temporary left and right array
    int l_curr = 0, r_curr = 0;
  
    // to store the current index
    // for output array
    int in = l_in;
  
    // two pointer merge for two sorted arrays
    while (l_curr + r_curr < l_c + r_c) {
        if (r_curr == r_c || (l_curr != l_c && 
            l_arr[l_curr] < r_arr[r_curr]))
            output[in] = l_arr[l_curr], l_curr++, in++;
        else
            output[in] = r_arr[r_curr], r_curr++, in++;
    }
}
  
// Code to drive merge-sort and
// create recursion tree
void divide(int l, int r, int* output,
            int arr[][n])
{
    if (l == r) {
  
        /* base step to initialize the output
           array before performing merge 
           operation */
        for (int i = 0; i < n; i++)
            output[l * n + i] = arr[l][i];
  
        return;
    }
  
    // to sort left half
    divide(l, (l + r) / 2, output, arr);
  
    // to sort right half
    divide((l + r) / 2 + 1, r, output, arr);
  
    // merge the left and right half
    merge(l, r, output);
}
  
// Driver Cunction
int main()
{
    // input 2D-array
    int arr[][n] = { { 5, 7, 15, 18 },
                     { 1, 8, 9, 17 },
                     { 1, 4, 7, 7 } };
  
    // Number of arrays
    int k = sizeof(arr) / sizeof(arr[0]);
  
    // Output array
    int* output = new int[n * k];
  
    divide(0, k - 1, output, arr);
  
    // Print merged array
    for (int i = 0; i < n * k; i++)
        cout << output[i] << " ";
  
    return 0;
}

chevron_right


Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// Java program to merge K sorted arrays 
import java.util.*;
  
class GFG
{
  
static int n = 4
  
// Function to perform merge operation 
static void merge(int l, int r, int[] output) 
    // to store the starting point of left 
    // and right array 
    int l_in = l * n, r_in = ((l + r) / 2 + 1) * n; 
  
    // to store the size of left and 
    // right array 
    int l_c = ((l + r) / 2 - l + 1) * n; 
    int r_c = (r - (l + r) / 2) * n; 
  
    // array to temporarily store left 
    // and right array 
    int l_arr[] = new int[l_c], r_arr[] = new int[r_c]; 
  
    // storing data in left array 
    for (int i = 0; i < l_c; i++) 
        l_arr[i] = output[l_in + i]; 
  
    // storing data in right array 
    for (int i = 0; i < r_c; i++) 
        r_arr[i] = output[r_in + i]; 
  
    // to store the current index of 
    // temporary left and right array 
    int l_curr = 0, r_curr = 0
  
    // to store the current index 
    // for output array 
    int in = l_in; 
  
    // two pointer merge for two sorted arrays 
    while (l_curr + r_curr < l_c + r_c)
    
        if (r_curr == r_c || (l_curr != l_c && 
            l_arr[l_curr] < r_arr[r_curr])) 
        {
            output[in] = l_arr[l_curr]; l_curr++; in++; 
        }
        else
        {
            output[in] = r_arr[r_curr]; r_curr++; in++; 
        }
    
  
// Code to drive merge-sort and 
// create recursion tree 
static void divide(int l, int r, int[] output, 
                                int arr[][]) 
    if (l == r)
    
  
        /* base step to initialize the output 
        array before performing merge 
        operation */
        for (int i = 0; i < n; i++) 
            output[l * n + i] = arr[l][i]; 
  
        return
    
  
    // to sort left half 
    divide(l, (l + r) / 2, output, arr); 
  
    // to sort right half 
    divide((l + r) / 2 + 1, r, output, arr); 
  
    // merge the left and right half 
    merge(l, r, output); 
  
// Driver Code
public static void main(String[] args) 
{
    // input 2D-array 
    int arr[][] = { { 5, 7, 15, 18 }, 
                    { 1, 8, 9, 17 }, 
                    { 1, 4, 7, 7 } }; 
  
    // Number of arrays 
    int k = arr.length; 
  
    // Output array 
    int[]output = new int[n * k]; 
  
    divide(0, k - 1, output, arr); 
  
    // Print merged array 
    for (int i = 0; i < n * k; i++) 
            System.out.print(output[i] + " ");
}
}
  
/* This code contributed by PrinciRaj1992 */

chevron_right


Python3

filter_none

edit
close

play_arrow

link
brightness_4
code

# Python3 program to merge K sorted arrays 
n = 4 ;
  
# Function to perform merge operation 
def merge(l, r, output) :
      
    # to store the starting point of 
    # left and right array 
    l_in = l * n ;
    r_in = ((l + r) // 2 + 1) * n; 
  
    # to store the size of left and 
    # right array 
    l_c = ((l + r) // 2 - l + 1) * n; 
    r_c = (r - (l + r) // 2) * n; 
  
    # array to temporarily store left 
    # and right array 
    l_arr = [0] * l_c; r_arr = [0] * r_c; 
  
    # storing data in left array 
    for i in range(l_c) :
        l_arr[i] = output[l_in + i]; 
  
    # storing data in right array 
    for i in range(r_c) :
        r_arr[i] = output[r_in + i]; 
  
    # to store the current index of 
    # temporary left and right array 
    l_curr = 0 ; r_curr = 0
  
    # to store the current index 
    # for output array 
    in1 = l_in; 
  
    # two pointer merge for two sorted arrays 
    while (l_curr + r_curr < l_c + r_c) :
        if (r_curr == r_c or (l_curr != l_c and
            l_arr[l_curr] < r_arr[r_curr])) :
            output[in1] = l_arr[l_curr]; 
            l_curr += 1; in1 += 1
        else :
            output[in1] = r_arr[r_curr];
            r_curr += 1; in1 += 1
  
# Code to drive merge-sort and 
# create recursion tree 
def divide(l, r, output, arr) :
      
    if (l == r) : 
  
        # base step to initialize the output 
        # array before performing merge 
        # operation 
        for i in range(n) :
            output[l * n + i] = arr[l][i]; 
  
        return
      
    # to sort left half 
    divide(l, (l + r) // 2, output, arr); 
  
    # to sort right half 
    divide((l + r) // 2 + 1, r, output, arr); 
  
    # merge the left and right half 
    merge(l, r, output); 
  
# Driver code 
if __name__ == "__main__" :
  
    # input 2D-array 
    arr = [[ 5, 7, 15, 18 ], 
           [ 1, 8, 9, 17 ], 
           [ 1, 4, 7, 7 ]]; 
      
    # Number of arrays 
    k = len(arr); 
      
    # Output array
    output = [0] * (n * k); 
      
    divide(0, k - 1, output, arr); 
      
    # Print merged array 
    for i in range(n * k) :
        print(output[i], end = " "); 
  
# This code is contributed by Ryuga

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// C# program to merge K sorted arrays 
using System;
  
class GFG
{
  
static int n = 4; 
  
// Function to perform merge operation 
static void merge(int l, int r, int[] output) 
    // to store the starting point of left 
    // and right array 
    int l_in = l * n, r_in = ((l + r) / 2 + 1) * n; 
  
    // to store the size of left and 
    // right array 
    int l_c = ((l + r) / 2 - l + 1) * n; 
    int r_c = (r - (l + r) / 2) * n; 
  
    // array to temporarily store left 
    // and right array 
    int []l_arr = new int[l_c];
    int []r_arr = new int[r_c]; 
  
    // storing data in left array 
    for (int i = 0; i < l_c; i++) 
        l_arr[i] = output[l_in + i]; 
  
    // storing data in right array 
    for (int i = 0; i < r_c; i++) 
        r_arr[i] = output[r_in + i]; 
  
    // to store the current index of 
    // temporary left and right array 
    int l_curr = 0, r_curr = 0; 
  
    // to store the current index 
    // for output array 
    int index = l_in; 
  
    // two pointer merge for two sorted arrays 
    while (l_curr + r_curr < l_c + r_c)
    
        if (r_curr == r_c || (l_curr != l_c && 
            l_arr[l_curr] < r_arr[r_curr])) 
        {
            output[index] = l_arr[l_curr]; l_curr++; index++; 
        }
        else
        {
            output[index] = r_arr[r_curr]; r_curr++; index++; 
        }
    
  
// Code to drive merge-sort and 
// create recursion tree 
static void divide(int l, int r, int[] output, 
                                int [,]arr) 
    if (l == r)
    
  
        /* base step to initialize the output 
        array before performing merge 
        operation */
        for (int i = 0; i < n; i++) 
            output[l * n + i] = arr[l, i]; 
  
        return
    
  
    // to sort left half 
    divide(l, (l + r) / 2, output, arr); 
  
    // to sort right half 
    divide((l + r) / 2 + 1, r, output, arr); 
  
    // merge the left and right half 
    merge(l, r, output); 
  
// Driver Code
public static void Main(String[] args) 
{
    // input 2D-array 
    int [,]arr = { { 5, 7, 15, 18 }, 
                    { 1, 8, 9, 17 }, 
                    { 1, 4, 7, 7 } }; 
  
    // Number of arrays 
    int k = arr.GetLength(0); 
  
    // Output array 
    int []output = new int[n * k]; 
  
    divide(0, k - 1, output, arr); 
  
    // Print merged array 
    for (int i = 0; i < n * k; i++) 
            Console.Write(output[i] + " ");
}
}
  
// This code has been contributed by 29AjayKumar

chevron_right


PHP

Output:

1 1 4 5 7 7 7 8 9 15 17 18

We can also solve this problem by using min-heap.



My Personal Notes arrow_drop_up

Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.