多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
# 合并 k 个排序的数组| 系列 1 > 原文: [https://www.geeksforgeeks.org/merge-k-sorted-arrays/](https://www.geeksforgeeks.org/merge-k-sorted-arrays/) 给定`k`个大小为`n`的排序数组,将它们合并并打印排序后的输出。 **示例**: > **输入**: > k = 3, n = 4 > arr [] [] = {{1, 3, 5, 7}, > {2, 4, 6, 8} , > {0, 9, 10, 11}}; > > **输出**: 0 1 2 3 4 5 6 7 8 9 10 11 > **说明**:输出数组是包含输入矩阵的所有元素的排序数组。 > > **输入**: > k = 3, n = 4 > arr [] [] = {{1, 5, 6, 8}, > {2, 4, 10, 12} , > {3, 7, 9, 11}, > {13, 14, 15, 16}}; > > **输出**: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 > **说明**:输出数组是包含输入矩阵的所有元素的排序数组。 **朴素的方法**:非常朴素的方法是创建大小为`n * k`的输出数组,然后将所有元素复制到输出数组中,然后进行排序。 * **算法**: 1. 创建大小为`n * k`的输出数组。 2. 从头到尾遍历矩阵并将所有元素插入输出数组。 3. 排序并打印输出数组。 * **实现**: ``` // 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; } ``` **输出**: ``` 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++ 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; } ``` **输出**: ``` 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)`。 **替代有效方法:** 这个想法是使用[最小堆](https://www.geeksforgeeks.org/binary-heap/)。 这种基于最小堆的解决方案具有相同的时间复杂度,即`O(NK log K)`。 但是对于[不同大小的数组](https://www.geeksforgeeks.org/merge-k-sorted-arrays-set-2-different-sized-arrays/),此解决方案效果更好。 该过程必须从创建最小堆并插入所有`k`个数组的第一个元素开始。 删除最小堆的根元素,并将其放在输出数组中,然后从已删除元素的数组中插入下一个元素。 为了获得结果,该步骤必须继续,直到最小堆中没有元素为止。 最小堆:最小堆是完整的二叉树,其中每个内部节点中的值小于或等于该节点的子级中的值。 将堆的元素映射到数组很简单:如果节点存储在索引`k`处,则其左子节点存储在索引`2k + 1`处,其右子节点存储在索引`2k + 2`处。 * **算法**: 1. 创建一个最小堆,并插入所有`k`个数组的第一个元素。 2. 运行循环,直到最小堆的大小大于零。 3. 删除最小堆的顶部元素并打印该元素。 4. 现在,从移除的元素所属的同一数组中插入下一个元素。 5. 如果数组中没有其他元素,则将`root`替换为`infinite`。替换完`root`后,堆放树。 * **实现**: ## C++ ``` // 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; } ``` ## 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 ``` ## Python3 ``` """ 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 ``` ## 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)`。 [**合并`k`个排序的数组| 第 2 组(不同大小的数组)**](https://www.geeksforgeeks.org/merge-k-sorted-arrays-set-2-different-sized-arrays/) 感谢 [vignesh](http://www.linkedin.com/in/vignesh4430) 提出了这个问题和初步的解决方案。 如果发现任何不正确的地方,或者想分享有关上述主题的更多信息,请发表评论