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 

A simple solution is to create an output array of size n*k and one by one copy all arrays to it. Finally, sort the output array using any O(n Log n) sorting algorithm. This approach takes O(nk Log nk) time.

One efficient solution is to first merge arrays into groups of 2. After first merging, we have k/2 arrays. We again merge arrays in groups, now we have k/4 arrays. We keep doing it unit we have one array left. The time complexity of this solution would O(nk Log k). How? Every merging in first iteration would take 2n time (merging two arrays of size n). Since there are total k/2 merging, total time in first iteration would be O(nk). Next iteration would also take O(nk). There will be total O(Log k) iterations, hence time complexity is O(nk Log k)



Another efficient solution is to use Min Heap. This Min Heap based solution has same time complexity which is O(nk Log k). But for different sized arrays, this solution works much better.

Following is detailed algorithm.
1. Create an output array of size n*k.
2. Create a min heap of size k and insert 1st element in all the arrays into the heap
3. Repeat following steps n*k times.
     a) Get minimum element from heap (minimum is always at root) and store it in output array.
     b) Replace heap root with next element from the array from which the element is extracted. If the array doesn’t have any more elements, then replace root with infinite. After replacing the root, heapify the tree.

Following 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 of size n each.
#include<iostream>
#include<limits.h>
using namespace std;
  
#define n 4
  
// A min heap node
struct MinHeapNode
{
    int element; // The element to be stored
    int i; // index of the array from which the element is taken
    int j; // index of the next element to be picked from array
};
  
// Prototype of a utility function to swap two min heap nodes
void swap(MinHeapNode *x, MinHeapNode *y);
  
// A class for Min Heap
class MinHeap
{
    MinHeapNode *harr; // pointer to array of elements in heap
    int heap_size; // size of min heap
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)
{
    int *output = new int[n*k];  // To store output array
  
    // 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++)
    {
        harr[i].element = arr[i][0]; // Store the first element
        harr[i].i = i;  // index of array
        harr[i].j = 1;  // Index of next element to be stored from array
    }
    MinHeap hp(harr, k); // Create the heap
  
    // 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
        else root.element =  INT_MAX; //INT_MAX is for infinite
  
        // 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


Output:

Merged array is
1 2 6 9 12 20 23 34 34 90 1000 2000

Time Complexity: The main step is 3rd step, the loop runs n*k times. In every iteration of loop, we call heapify which takes O(Logk) time. Therefore, the time complexity is O(nk Logk).

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



My Personal Notes arrow_drop_up