📜  合并 k 个排序数组 |设置 1

📅  最后修改于: 2021-10-28 01:50:43             🧑  作者: Mango

给定 k 个大小为 n 的排序数组,合并它们并打印排序后的输出。

例子:

朴素的方法非常朴素的方法是创建一个大小为 n * k 的输出数组,然后将所有元素复制到输出数组中,然后进行排序。

  • 算法:
    1. 创建一个大小为 n * k 的输出数组。
    2. 从头到尾遍历矩阵并将所有元素插入输出数组中。
    3. 排序并打印输出数组。
  • 执行:
C++14
// C++ program to merge k sorted arrays of size n each.
#include
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


Java
// Java program to merge k sorted arrays of size n each.
 
import java.io.*;
import java.util.*;
 
class GFG {
 
    // 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.
    public static void mergeKArrays(int[][] arr, int a,
                                    int[] output)
    {
        int c = 0;
 
        // traverse the matrix
        for (int i = 0; i < a; i++) {
            for (int j = 0; j < 4; j++)
                output[c++] = arr[i][j];
        }
 
        // sort the array
        Arrays.sort(output);
    }
 
    // A utility function to print array elements
    public static void printArray(int[] arr, int size)
    {
        for (int i = 0; i < size; i++)
            System.out.print(arr[i] + " ");
    }
   
    // Driver program to test above functions
    public static void main(String[] args)
    {
        int[][] arr = { { 2, 6, 12, 34 },
                        { 1, 9, 20, 1000 },
                        { 23, 34, 90, 2000 } };
        int k = 4;
        int n = 3;
        int[] output = new int[n * k];
 
        mergeKArrays(arr, n, output);
 
        System.out.println("Merged array is ");
        printArray(output, n * k);
    }
}


C#
// C# program to merge k sorted arrays of size n each.
using System;
public class GFG
{
 
  // 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 readonly sorted output.
  public static void mergeKArrays(int[,] arr, int a,
                                  int[] output)
  {
    int c = 0;
 
    // traverse the matrix
    for (int i = 0; i < a; i++)
    {
      for (int j = 0; j < 4; j++)
        output[c++] = arr[i,j];
    }
 
    // sort the array
    Array.Sort(output);
  }
 
  // A utility function to print array elements
  public static void printArray(int[] arr, int size)
  {
    for (int i = 0; i < size; i++)
      Console.Write(arr[i] + " ");
  }
 
  // Driver program to test above functions
  public static void Main(String[] args)
  {
    int[,] arr = { { 2, 6, 12, 34 },
                  { 1, 9, 20, 1000 },
                  { 23, 34, 90, 2000 } };
    int k = 4;
    int n = 3;
    int[] output = new int[n * k];
    mergeKArrays(arr, n, output);
    Console.WriteLine("Merged array is ");
    printArray(output, n * k);
  }
}
 
// This code is contributed by Rajput-Ji


Javascript


C++14
// C++ program to merge k sorted arrays of size n each.
#include
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


Java
// Java program to merge k sorted arrays of size n each.
import java.util.*;
 
class GFG{
  static final int n = 4;
 
  // Merge arr1[0..n1-1] and arr2[0..n2-1] into
  // arr3[0..n1+n2-1]
  static void mergeArrays(int arr1[], int arr2[], int n1,
                          int n2, int arr3[])
  {
    int i = 0, j = 0, k = 0;
 
    // Traverse both array
    while (i


C#
// C# program to merge k sorted arrays of size n each.
using System;
 
class GFG{
 
static readonly int n = 4;
 
public static int[] GetRow(int[,] matrix, int row)
{
    var rowLength = matrix.GetLength(1);
    var rowVector = new int[rowLength];
     
    for(var i = 0; i < rowLength; i++)
        rowVector[i] = matrix[row, i];
     
    return rowVector;
}
     
// Merge arr1[0..n1-1] and arr2[0..n2-1] into
// arr3[0..n1+n2-1]
static 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
static void printArray(int []arr, int size)
{
    for(int i = 0; i < size; i++)
        Console.Write(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 readonly sorted output.
static void mergeKArrays(int [,]arr, 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(GetRow(arr, i), GetRow(arr, j),
                    n, n, output);
        return;
    }
 
    // Output arrays
    int []out1 = new int[n*(((i + j) / 2) - i + 1)];
    int []out2 = new int[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 code
public static void Main(String[] args)
{
 
    // Change n at the top to change number of elements
    // in an array
    int [,]arr =  { { 2, 6, 12, 34 },
                    { 1, 9, 20, 1000 },
                    { 23, 34, 90, 2000 } };
    int k = arr.GetLength(0);
    int []output = new int[n * k];
    mergeKArrays(arr, 0, 2, output);
     
    Console.Write("Merged array is " + "\n");
    printArray(output, n * k);
}
}
 
// This code is contributed by Rajput-Ji


Javascript


C++
// C++ program to merge k sorted
// arrays of size n each.
#include
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;
}


Java
// 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


C#
// 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


输出:
Merged array is 
1 2 6 9 12 20 23 34 34 90 1000 2000
  • 复杂度分析:
    • 时间复杂度: O(n*k*log(n*k))。
      因为结果数组的大小为 N*k。
    • 空间复杂度: O(n*k),输出数组大小为 n*k。

有效的方法该过程可能从将数组合并为两个一组开始。第一次合并后,我们有 k/2 个数组。再次按组合并数组,现在我们有 k/4 个数组。这类似于归并排序。将 k 个数组分成包含相同数量数组的两半,直到一组中有两个数组。然后以自底向上的方式合并数组。

  • 算法:
    1. 创建一个递归函数,它接受 k 个数组并返回输出数组。
    2. 在递归函数,如果 k 的值为 1 则返回数组,否则如果 k 的值为 2 则在线性时间内合并两个数组并返回数组。
    3. 如果k的值大于2,然后除以该组k个元素的成相等的两半,并递归地调用函数,即,0到K / 2阵列中的一个递归函数以及k / 2到k阵列中的另一个递归函数。
    4. 打印输出数组。
  • 执行:

C++14

// C++ program to merge k sorted arrays of size n each.
#include
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

Java

// Java program to merge k sorted arrays of size n each.
import java.util.*;
 
class GFG{
  static final int n = 4;
 
  // Merge arr1[0..n1-1] and arr2[0..n2-1] into
  // arr3[0..n1+n2-1]
  static void mergeArrays(int arr1[], int arr2[], int n1,
                          int n2, int arr3[])
  {
    int i = 0, j = 0, k = 0;
 
    // Traverse both array
    while (i

C#

// C# program to merge k sorted arrays of size n each.
using System;
 
class GFG{
 
static readonly int n = 4;
 
public static int[] GetRow(int[,] matrix, int row)
{
    var rowLength = matrix.GetLength(1);
    var rowVector = new int[rowLength];
     
    for(var i = 0; i < rowLength; i++)
        rowVector[i] = matrix[row, i];
     
    return rowVector;
}
     
// Merge arr1[0..n1-1] and arr2[0..n2-1] into
// arr3[0..n1+n2-1]
static 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
static void printArray(int []arr, int size)
{
    for(int i = 0; i < size; i++)
        Console.Write(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 readonly sorted output.
static void mergeKArrays(int [,]arr, 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(GetRow(arr, i), GetRow(arr, j),
                    n, n, output);
        return;
    }
 
    // Output arrays
    int []out1 = new int[n*(((i + j) / 2) - i + 1)];
    int []out2 = new int[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 code
public static void Main(String[] args)
{
 
    // Change n at the top to change number of elements
    // in an array
    int [,]arr =  { { 2, 6, 12, 34 },
                    { 1, 9, 20, 1000 },
                    { 23, 34, 90, 2000 } };
    int k = arr.GetLength(0);
    int []output = new int[n * k];
    mergeKArrays(arr, 0, 2, output);
     
    Console.Write("Merged array is " + "\n");
    printArray(output, n * k);
}
}
 
// This code is contributed by Rajput-Ji

Javascript


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

复杂度分析:

  • 时间复杂度: O(n * k * log k)。
    有 log k 个级别,因为在每个级别中,k 个数组被分成两半,并且在每个级别上遍历 k 个数组。所以时间复杂度是 O( n * k )。
  • 空间复杂度: O(n * k * log k)。
    在每个级别中都需要 O( n*k ) 空间所以空间复杂度是 O( n * k * log k)。

替代高效方法:这个想法是使用最小堆。这个基于 MinHeap 的解决方案具有相同的时间复杂度,即 O(NK log K)。但是对于不同且特定大小的数组,此解决方案效果更好。该过程必须从创建一个 MinHeap 并插入所有 k 个数组的第一个元素开始。移除 Minheap 的根元素并将其放入输出数组中,然后插入移除元素数组中的下一个元素。要获得结果,该步骤必须继续,直到 MinHeap 中没有元素为止。

MinHeap: Min-Heap 是一个完整的二叉树,其中每个内部节点中的值小于或等于该节点的子节点中的值。将堆的元素映射到数组是微不足道的:如果一个节点存储在索引 k 处,则其左子节点存储在索引 2k + 1 处,其右子节点存储在索引 2k + 2 处。

  • 算法:
    1. 创建一个最小堆并插入所有 k 个数组的第一个元素。
    2. 运行一个循环,直到 MinHeap 的大小大于零。
    3. 删除 MinHeap 的顶部元素并打印该元素。
    4. 现在从删除元素所属的同一数组中插入下一个元素。
    5. 如果数组没有更多元素,则将root替换为infinite。替换root后,将树堆化。

执行:

C++

// C++ program to merge k sorted
// arrays of size n each.
#include
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;
}

Java

// 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

C#

// 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
输出:
Merged array is 
1 2 6 9 12 20 23 34 34 90 1000 2000

复杂度分析:

  • 时间复杂度: O( n * k * log k),在最小堆中插入和删除需要 log k 时间。所以总时间复杂度是 O( n * k * log k)
  • 空间复杂度: O(k),如果没有存储输出,那么唯一需要的空间是 k 个元素的最小堆。所以空间复杂度是 O(k)。

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程