Merge k sorted arrays | Set 1

Given k sorted arrays of size n each, merge them and print the sorted output.

Example:

Input:
k = 3, n = 4
arr[][] = { {1, 3, 5, 7},
{2, 4, 6, 8},
{0, 9, 10, 11}} ;

Output: 0 1 2 3 4 5 6 7 8 9 10 11
Explanation: The output array is a sorted array that contains all the elements of the input matrix.

Input:
k = 3, n = 4
arr[][] = { {1, 5, 6, 8},
{2, 4, 10, 12},
{3, 7, 9, 11},
{13, 14, 15, 16}} ;



Output: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Explanation: The output array is a sorted array that contains all the elements of the input matrix.

Naive Approach: The very naive method is to create an output array of size n * k and then copy all the elements into the output array followed by sorting.

  • Algorithm:
    1. Create a output array of size n * k.
    2. Traverse the matrix from start to end and insert all the elements in output array.
    3. Sort and print the output array.
  • Implementation:

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    // C++ program to merge k sorted arrays of size n each.
    #include<bits/stdc++.h>
    using namespace std;
    #define n 4
      
      
    // A utility function to print array elements
    void printArray(int arr[], int size)
    {
       for (int i=0; i < size; i++)
           cout << arr[i] << " ";
    }
      
    // This function takes an array of arrays as an argument and
    // All arrays are assumed to be sorted. It merges them together
    // and prints the final sorted output.
    void mergeKArrays(int arr[][n], int a, int output[])
    {
        int c=0;
          
        //traverse the matrix
        for(int i=0; i<a; i++)
        {
            for(int j=0; j<n ;j++)
                output[c++]=arr[i][j];
        }
          
        //sort the array
        sort(output,output + n*a);
          
    }
       
       
    // Driver program to test above functions
    int main()
    {
        // Change n at the top to change number of elements
        // in an array
        int arr[][n] =  {{2, 6, 12, 34},
                         {1, 9, 20, 1000},
                         {23, 34, 90, 2000}};
        int k = sizeof(arr)/sizeof(arr[0]);
          
        int output[n*k];
          
        mergeKArrays(arr, 3, output);
       
        cout << "Merged array is " << endl;
        printArray(output, n*k);
       
        return 0;
    }

    chevron_right

    
    

    Output:

    Merged array is 
    1 2 6 9 12 20 23 34 34 90 1000 2000
    
  • Complexity Analysis:

    • Time Complexity :O(n*k*log(n*k)).
      since resulting array is of N*k size.
    • Space Complexity :O(n*k), The output array is of size n*k.

Efficient Approach The process might begin with merging arrays into groups of two. After the first merge, we have k/2 arrays. Again merge arrays in groups, now we have k/4 arrays. This is similar to merge sort. Divide k arrays into two halves containing an equal number of arrays until there are two arrays in a group. This is followed by merging the arrays in a bottom-up manner.

  • Algorithm:
    1. Create a recursive function which takes k arrays and returns the output array.
    2. In the recursive function, if the value of k is 1 then return the array else if the value of k is 2 then merge the two arrays in linear time and return the array.
    3. If the value of k is greater than 2 then divide the group of k elements into two equal halves and recursively call the function, i.e 0 to k/2 array in one recursive function and k/2 to k array in another recursive function.
    4. Print the output array.
  • Implementation:

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    // C++ program to merge k sorted arrays of size n each.
    #include<bits/stdc++.h>
    using namespace std;
    #define n 4
      
    // Merge arr1[0..n1-1] and arr2[0..n2-1] into 
    // arr3[0..n1+n2-1] 
    void mergeArrays(int arr1[], int arr2[], int n1, 
                                 int n2, int arr3[]) 
        int i = 0, j = 0, k = 0; 
        
        // Traverse both array 
        while (i<n1 && j <n2) 
        
            // Check if current element of first 
            // array is smaller than current element 
            // of second array. If yes, store first 
            // array element and increment first array 
            // index. Otherwise do same with second array 
            if (arr1[i] < arr2[j]) 
                arr3[k++] = arr1[i++]; 
            else
                arr3[k++] = arr2[j++]; 
        
        
        // Store remaining elements of first array 
        while (i < n1) 
            arr3[k++] = arr1[i++]; 
        
        // Store remaining elements of second array 
        while (j < n2) 
            arr3[k++] = arr2[j++]; 
    }
      
    // A utility function to print array elements
    void printArray(int arr[], int size)
    {
       for (int i=0; i < size; i++)
           cout << arr[i] << " ";
    }
      
    // This function takes an array of arrays as an argument and
    // All arrays are assumed to be sorted. It merges them together
    // and prints the final sorted output.
    void mergeKArrays(int arr[][n],int i,int j, int output[])
    {
        //if one array is in range
        if(i==j)
        {
            for(int p=0; p < n; p++)
            output[p]=arr[i][p];
            return;
        }
          
        //if only two arrays are left them merge them 
        if(j-i==1)
        {
            mergeArrays(arr[i],arr[j],n,n,output);
            return;
        }
          
        //output arrays 
        int out1[n*(((i+j)/2)-i+1)],out2[n*(j-((i+j)/2))];
          
        //divide the array into halves
        mergeKArrays(arr,i,(i+j)/2,out1);
        mergeKArrays(arr,(i+j)/2+1,j,out2);
          
        //merge the output array
        mergeArrays(out1,out2,n*(((i+j)/2)-i+1),n*(j-((i+j)/2)),output);
          
    }
       
       
    // Driver program to test above functions
    int main()
    {
        // Change n at the top to change number of elements
        // in an array
        int arr[][n] =  {{2, 6, 12, 34},
                         {1, 9, 20, 1000},
                         {23, 34, 90, 2000}};
        int k = sizeof(arr)/sizeof(arr[0]);
        int output[n*k];
        mergeKArrays(arr,0,2, output);
       
        cout << "Merged array is " << endl;
        printArray(output, n*k);
       
        return 0;
    }

    chevron_right

    
    

    Output:



    Merged array is 
    1 2 6 9 12 20 23 34 34 90 1000 2000
    
  • Complexity Analysis:

    • Time Complexity: O( n * k * log k).
      There are log k levels as in each level the k arrays are divided in half and at each level the k arrays are traversed. So time Complexity is O( n * k ).
    • Space Complexity: O( n * k * log k).
      In each level O( n*k ) space is required So Space Complexity is O( n * k * log k).


Alternative Efficient Approach: The idea is to use Min Heap. This MinHeap based solution has the same time complexity which is O(NK log K). But for a different and particular sized array, this solution works much better. The process must start with creating a MinHeap and inserting the first element of all the k arrays. Remove the root element of Minheap and put it in the output array and insert the next element from the array of removed element. To get the result the step must continue until there is no element in the MinHeap left.
MinHeap: A Min-Heap is a complete binary tree in which the value in each internal node is smaller than or equal to the values in the children of that node. Mapping the elements of a heap into an array is trivial: if a node is stored at index k, then its left child is stored at index 2k + 1 and its right child at index 2k + 2.

  • Algorithm:
    1. Create a min Heap and insert the first element of all k arrays.
    2. Run a loop until the size of MinHeap is greater than zero.
    3. Remove the top element of the MinHeap and print the element.
    4. Now insert the next element from the same array in which the removed element belonged.
    5. If the array doesn’t have any more elements, then replace root with infinite.After replacing the root, heapify the tree.
  • Implementation:

    C++

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    // C++ program to merge k sorted 
    // arrays of size n each.
    #include<bits/stdc++.h>
    using namespace std;
      
    #define n 4
      
    // A min-heap node
    struct MinHeapNode
    {
    // The element to be stored
        int element;
      
    // index of the array from which the element is taken
        int i;
      
    // index of the next element to be picked from the array 
        int j;
    };
      
    // Prototype of a utility function to swap two min-heap nodes
    void swap(MinHeapNode *x, MinHeapNode *y);
      
    // A class for Min Heap
    class MinHeap
    {
      
    // pointer to array of elements in heap
        MinHeapNode *harr; 
      
    // size of min heap
        int heap_size; 
    public:
        // Constructor: creates a min heap of given size
        MinHeap(MinHeapNode a[], int size);
      
        // to heapify a subtree with root at given index
        void MinHeapify(int );
      
        // to get index of left child of node at index i
        int left(int i) { return (2*i + 1); }
      
        // to get index of right child of node at index i
        int right(int i) { return (2*i + 2); }
      
        // to get the root
        MinHeapNode getMin() { return harr[0]; }
      
        // to replace root with new node x and heapify() new root
        void replaceMin(MinHeapNode x) { harr[0] = x;  MinHeapify(0); }
    };
      
    // This function takes an array of arrays as an argument and
    // All arrays are assumed to be sorted. It merges them together
    // and prints the final sorted output.
    int *mergeKArrays(int arr[][n], int k)
    {
      
    // To store output array
        int *output = new int[n*k];  
      
        // Create a min heap with k heap nodes. 
        // Every heap node has first element of an array
        MinHeapNode *harr = new MinHeapNode[k];
        for (int i = 0; i < k; i++)
        {
      
    // Store the first element
            harr[i].element = arr[i][0]; 
      
    // index of array
            harr[i].i = i;
      
     // Index of next element to be stored from the array
            harr[i].j = 1; 
        }
      
    // Create the heap
        MinHeap hp(harr, k); 
      
        // Now one by one get the minimum element from min
        // heap and replace it with next element of its array
        for (int count = 0; count < n*k; count++)
        {
            // Get the minimum element and store it in output
            MinHeapNode root = hp.getMin();
            output[count] = root.element;
      
            // Find the next elelement that will replace current
            // root of heap. The next element belongs to same
            // array as the current root.
            if (root.j < n)
            {
                root.element = arr[root.i][root.j];
                root.j += 1;
            }
            // If root was the last element of its array
    // INT_MAX is for infinite        
    else root.element =  INT_MAX; 
      
            // Replace root with next element of array
            hp.replaceMin(root);
        }
      
        return output;
    }
      
    // FOLLOWING ARE IMPLEMENTATIONS OF 
    // STANDARD MIN HEAP METHODS FROM CORMEN BOOK
    // Constructor: Builds a heap from a given 
    // array a[] of given size
    MinHeap::MinHeap(MinHeapNode a[], int size)
    {
        heap_size = size;
        harr = a;  // store address of array
        int i = (heap_size - 1)/2;
        while (i >= 0)
        {
            MinHeapify(i);
            i--;
        }
    }
      
    // A recursive method to heapify a 
    // subtree with root at given index. 
    // This method assumes that the subtrees 
    // are already heapified
    void MinHeap::MinHeapify(int i)
    {
        int l = left(i);
        int r = right(i);
        int smallest = i;
        if (l < heap_size && harr[l].element < harr[i].element)
            smallest = l;
        if (r < heap_size && harr[r].element < harr[smallest].element)
            smallest = r;
        if (smallest != i)
        {
            swap(&harr[i], &harr[smallest]);
            MinHeapify(smallest);
        }
    }
      
    // A utility function to swap two elements
    void swap(MinHeapNode *x, MinHeapNode *y)
    {
        MinHeapNode temp = *x;  *x = *y;  *y = temp;
    }
      
    // A utility function to print array elements
    void printArray(int arr[], int size)
    {
       for (int i=0; i < size; i++)
           cout << arr[i] << " ";
    }
      
    // Driver program to test above functions
    int main()
    {
        // Change n at the top to change number of elements
        // in an array
        int arr[][n] =  {{2, 6, 12, 34},
                         {1, 9, 20, 1000},
                         {23, 34, 90, 2000}};
        int k = sizeof(arr)/sizeof(arr[0]);
      
        int *output = mergeKArrays(arr, k);
      
        cout << "Merged array is " << endl;
        printArray(output, n*k);
      
        return 0;
    }

    chevron_right

    
    

    Java

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    // Java program to merge k sorted 
    // arrays of size n each.
      
    // A min heap node
    class MinHeapNode
    {
        int element; // The element to be stored
          
         // index of the array from 
         // which the element is taken
        int i;
          
        // index of the next element 
        // to be picked from array
        int j; 
      
        public MinHeapNode(int element, int i, int j)
        {
            this.element = element;
            this.i = i;
            this.j = j;
        }
    };
      
    // A class for Min Heap
    class MinHeap
    {
        MinHeapNode[] harr; // Array of elements in heap
        int heap_size; // Current number of elements in min heap
      
        // Constructor: Builds a heap from 
        // a given array a[] of given size
        public MinHeap(MinHeapNode a[], int size)
        {
            heap_size = size;
            harr = a;
            int i = (heap_size - 1)/2;
            while (i >= 0)
            {
                MinHeapify(i);
                i--;
            }
        }
      
        // A recursive method to heapify a subtree 
        // with the root at given index This method
        // assumes that the subtrees are already heapified
        void MinHeapify(int i)
        {
            int l = left(i);
            int r = right(i);
            int smallest = i;
            if (l < heap_size && harr[l].element < harr[i].element)
                smallest = l;
            if (r < heap_size && harr[r].element < harr[smallest].element)
                smallest = r;
            if (smallest != i)
            {
                swap(harr, i, smallest);
                MinHeapify(smallest);
            }
        }
      
        // to get index of left child of node at index i
        int left(int i) { return (2*i + 1); }
      
        // to get index of right child of node at index i
        int right(int i) { return (2*i + 2); }
      
        // to get the root
        MinHeapNode getMin() 
        {
            if(heap_size <= 0
            {
                System.out.println("Heap underflow");
                return null;
            }
            return harr[0];
        }
      
        // to replace root with new node 
        // "root" and heapify() new root
        void replaceMin(MinHeapNode root) {
            harr[0] = root;
            MinHeapify(0);
        }
      
        // A utility function to swap two min heap nodes
        void swap(MinHeapNode[] arr, int i, int j) {
            MinHeapNode temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
      
        // A utility function to print array elements
        static void printArray(int[] arr) {
            for(int i : arr)
                System.out.print(i + " ");
            System.out.println();
        }
      
        // This function takes an array of 
        // arrays as an argument and All 
        // arrays are assumed to be sorted. 
        // It merges them together and 
        // prints the final sorted output.
        static void mergeKSortedArrays(int[][] arr, int k) 
        {
            MinHeapNode[] hArr = new MinHeapNode[k];
            int resultSize = 0;
            for(int i = 0; i < arr.length; i++) 
            {
                MinHeapNode node = new MinHeapNode(arr[i][0],i,1);
                hArr[i] = node;
                resultSize += arr[i].length;
            }
      
            // Create a min heap with k heap nodes. Every heap node
            // has first element of an array
            MinHeap mh = new MinHeap(hArr, k);
      
            int[] result = new int[resultSize];     // To store output array
      
            // Now one by one get the minimum element from min
            // heap and replace it with next element of its array
            for(int i = 0; i < resultSize; i++) 
            {
      
                // Get the minimum element and store it in result
                MinHeapNode root = mh.getMin();
                result[i] = root.element;
      
                // Find the next element that will replace current
                // root of heap. The next element belongs to same
                // array as the current root.
                if(root.j < arr[root.i].length)
                    root.element = arr[root.i][root.j++];
                // If root was the last element of its array
                else
                    root.element = Integer.MAX_VALUE;
      
                // Replace root with next element of array 
                mh.replaceMin(root);
            }
      
            printArray(result);
      
        }
      
        // Driver code
        public static void main(String args[]){
            int[][] arr= {{2, 6, 12, 34},
                    {1, 9, 20, 1000},
                    {23, 34, 90, 2000}};
      
            System.out.println("Merged array is :");
      
            mergeKSortedArrays(arr,arr.length);
        }
    };
      
    // This code is contributed by shubham96301

    chevron_right

    
    

    Python3

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    """
    Python3 program to merge k sorted arrays of size n each
    """
    import sys
    from typing import List, Optional
    Matrix = List[List[int]]
      
      
    class MinHeapNode:
        def __init__(self, el, i, j):
            self.element = el # the element to be sorted
            self.i = i         # index of array from which element is taken
            self.j = j         # index of next element to be picked from array
      
      
    class MinHeap:
        def __init__(self, ar: List[MinHeapNode], size: int):
            self.heap_size = size
            self.heap_arr = ar
            i = (self.heap_size - 1) // 2
            while i >= 0:
                self.min_heapify(i)
                i -= 1
      
        """
        A recursive method to heapify a subtree
        with the root at given index. This method
        assumes that the subtree are already heapified
        """
        def min_heapify(self, i):
            l = left(i)
            r = right(i)
            smallest = i
            if l < self.heap_size and self.heap_arr[l].element < self.heap_arr[i].element:
                smallest = l
            if r < self.heap_size and self.heap_arr[r].element < self.heap_arr[smallest].element:
                smallest = r
            if smallest != i:
                swap(self.heap_arr, i, smallest)
                self.min_heapify(smallest)
      
        def get_min(self) -> Optional:
            if self.heap_size <= 0:
                print('Heap underflow')
                return None
            return self.heap_arr[0]
      
        # Replace root with new root
        def replace_min(self, root):
            self.heap_arr[0] = root
            self.min_heapify(0)
      
      
    def left(i):
        return 2 * i + 1
      
      
    def right(i):
        return 2 * i + 2
      
      
    def swap(arr: List[MinHeapNode], i, j):
        temp = arr[i]
        arr[i] = arr[j]
        arr[j] = temp
      
      
    def merge_k_sorted_arrays(arr: Matrix, k: int):
        h_arr = []
        result_size = 0
        for i in range(len(arr)):
            node = MinHeapNode(arr[i][0], i, 1)
            h_arr.append(node)
            result_size += len(arr[i])
      
        min_heap = MinHeap(h_arr, k)
        result = [0]*result_size
        for i in range(result_size):
            root = min_heap.get_min()
            result[i] = root.element
            if root.j < len(arr[root.i]):
                root.element = arr[root.i][root.j]
                root.j += 1
            else:
                root.element = sys.maxsize
            min_heap.replace_min(root)
        for x in result:
            print(x, end=' ')
        print()
      
      
    if __name__ == '__main__':
        arr = [
            [2, 6, 12, 34],
            [1, 9, 20, 1000],
            [23, 34, 90, 2000]
        ]
        print('Merged Array is:')
        merge_k_sorted_arrays(arr, len(arr))
      
    # The code is contributed by Rajat Srivastava

    chevron_right

    
    

    C#

    filter_none

    edit
    close

    play_arrow

    link
    brightness_4
    code

    // C# program to merge k sorted 
    // arrays of size n each.
    using System;
      
    // A min heap node
    public class MinHeapNode
    {
        public int element; // The element to be stored
          
        // index of the array from 
        // which the element is taken
        public int i;
          
        // index of the next element 
        // to be picked from array
        public int j; 
      
        public MinHeapNode(int element, int i, int j)
        {
            this.element = element;
            this.i = i;
            this.j = j;
        }
    };
      
    // A class for Min Heap
    public class MinHeap
    {
        MinHeapNode[] harr; // Array of elements in heap
        int heap_size; // Current number of elements in min heap
      
        // Constructor: Builds a heap from 
        // a given array a[] of given size
        public MinHeap(MinHeapNode []a, int size)
        {
            heap_size = size;
            harr = a;
            int i = (heap_size - 1) / 2;
            while (i >= 0)
            {
                MinHeapify(i);
                i--;
            }
        }
      
        // A recursive method to heapify a subtree 
        // with the root at given index This method
        // assumes that the subtrees are already heapified
        void MinHeapify(int i)
        {
            int l = left(i);
            int r = right(i);
            int smallest = i;
            if (l < heap_size && 
                harr[l].element < harr[i].element)
                smallest = l;
            if (r < heap_size && 
                harr[r].element < harr[smallest].element)
                smallest = r;
            if (smallest != i)
            {
                swap(harr, i, smallest);
                MinHeapify(smallest);
            }
        }
      
        // to get index of left child of node at index i
        int left(int i) { return (2 * i + 1); }
      
        // to get index of right child of node at index i
        int right(int i) { return (2 * i + 2); }
      
        // to get the root
        MinHeapNode getMin() 
        {
            if(heap_size <= 0) 
            {
                Console.WriteLine("Heap underflow");
                return null;
            }
            return harr[0];
        }
      
        // to replace root with new node 
        // "root" and heapify() new root
        void replaceMin(MinHeapNode root)
        {
            harr[0] = root;
            MinHeapify(0);
        }
      
        // A utility function to swap two min heap nodes
        void swap(MinHeapNode[] arr, int i, int j) 
        {
            MinHeapNode temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
      
        // A utility function to print array elements
        static void printArray(int[] arr) 
        {
            foreach(int i in arr)
                Console.Write(i + " ");
            Console.WriteLine();
        }
      
        // This function takes an array of 
        // arrays as an argument and All 
        // arrays are assumed to be sorted. 
        // It merges them together and 
        // prints the final sorted output.
        static void mergeKSortedArrays(int[,] arr, int k) 
        {
            MinHeapNode[] hArr = new MinHeapNode[k];
            int resultSize = 0;
            for(int i = 0; i < arr.GetLength(0); i++) 
            {
                MinHeapNode node = new MinHeapNode(arr[i, 0], i, 1);
                hArr[i] = node;
                resultSize += arr.GetLength(1);
            }
      
            // Create a min heap with k heap nodes. 
            // Every heap node has first element of an array
            MinHeap mh = new MinHeap(hArr, k);
      
            int[] result = new int[resultSize];     // To store output array
      
            // Now one by one get the minimum element 
            // from min heap and replace it with 
            // next element of its array
            for(int i = 0; i < resultSize; i++) 
            {
      
                // Get the minimum element and
                // store it in result
                MinHeapNode root = mh.getMin();
                result[i] = root.element;
      
                // Find the next element that will 
                // replace current root of heap. 
                // The next element belongs to same
                // array as the current root.
                if(root.j < arr.GetLength(1))
                    root.element = arr[root.i,root.j++];
                      
                // If root was the last element of its array
                else
                    root.element = int.MaxValue;
      
                // Replace root with next element of array 
                mh.replaceMin(root);
            }
            printArray(result);
        }
      
        // Driver code
        public static void Main(String []args)
        {
            int[,] arr = {{2, 6, 12, 34},
                          {1, 9, 20, 1000},
                          {23, 34, 90, 2000}};
      
            Console.WriteLine("Merged array is :");
      
            mergeKSortedArrays(arr, arr.GetLength(0));
        }
    };
      
    // This code is contributed by 29AjayKumar

    chevron_right

    
    

    Output:

    Merged array is 
    1 2 6 9 12 20 23 34 34 90 1000 2000
    
  • Complexity Analysis:

    • Time Complexity :O( n * k * log k), Insertion and deletion in a Min Heap requires log k time. So the Overall time compelxity is O( n * k * log k)
    • Space Complexity :O(k), If Output is not stored then the only space required is the Min-Heap of k elements. So space Comeplexity is O(k).

Merge k sorted arrays | Set 2 (Different Sized Arrays)

Thanks to vignesh for suggesting this problem and initial solution. Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.




My Personal Notes arrow_drop_up