给出 k 个排序数组,每个数组的大小为N ,任务是将它们合并为一个排序数组。
例子:
Input: arr[][] = {{5, 7, 15, 18},
{1, 8, 9, 17},
{1, 4, 7, 7}}
Output: {1, 1, 4, 5, 7, 7, 7, 8, 9, 15, 17, 18}
Input: arr[][] = {{3, 2, 1}
{6, 5, 4}}
Output: {1, 2, 3, 4, 5, 6}
先决条件:归并排序
简单的方法:一个简单的解决方案是将所有数组一个接一个地附加并排序。
C++14
// C++ program to merge K
// sorted arrays
#include
using namespace std;
#define N 4
// Merge and sort k arrays
void merge_and_sort(
int* output, int arr[][N],
int n, int k)
{
// Put the elements in sorted array.
for (int i = 0; i < k; i++) {
for (int j = 0; j < n; j++) {
output[i * n + j] = arr[i][j];
}
}
// Sort the output array
sort(output, output + n * k);
}
// Driver Function
int main()
{
// Input 2D-array
int arr[][N] = { { 5, 7, 15, 18 },
{ 1, 8, 9, 17 },
{ 1, 4, 7, 7 } };
int n = N;
// Number of arrays
int k = sizeof(arr) / sizeof(arr[0]);
// Output array
int* output = new int[n * k];
merge_and_sort(output, arr, n, k);
// Print merged array
for (int i = 0; i < n * k; i++)
cout << output[i] << " ";
return 0;
}
Java
// Java program to merge K
// sorted arrays
import java.util.*;
class GFG
{
static int N = 4;
// Merge and sort k arrays
static void merge_and_sort(int output[], int arr[][],
int n, int k)
{
// Put the elements in sorted array.
for (int i = 0; i < k; i++)
{
for (int j = 0; j < n; j++)
{
output[i * n + j] = arr[i][j];
}
}
// Sort the output array
Arrays.sort(output);
}
// Driver code
public static void main(String[] args)
{
// Input 2D-array
int arr[][] = { { 5, 7, 15, 18 },
{ 1, 8, 9, 17 },
{ 1, 4, 7, 7 } };
int n = N;
// Number of arrays
int k = arr.length;
// Output array
int output[] = new int[n * k];
merge_and_sort(output, arr, n, k);
// Print merged array
for (int i = 0; i < n * k; i++)
System.out.print(output[i] + " ");
}
}
// This code is contributed by divyesh072019
Python3
# Python3 program to merge K
# sorted arrays
N = 4
# Merge and sort k arrays
def merge_and_sort(output, arr, n, k):
# Put the elements in sorted array.
for i in range(k):
for j in range(n):
output[i * n + j] = arr[i][j];
# Sort the output array
output.sort()
# Driver Function
if __name__=='__main__':
# Input 2D-array
arr = [ [ 5, 7, 15, 18 ],
[ 1, 8, 9, 17 ],
[ 1, 4, 7, 7 ] ];
n = N;
# Number of arrays
k = len(arr)
# Output array
output = [0 for i in range(n * k)]
merge_and_sort(output, arr, n, k);
# Print merged array
for i in range(n * k):
print(output[i], end = ' ')
# This code is contributed by rutvik_56.
C#
// C# program to merge K
// sorted arrays
using System;
class GFG
{
static int N = 4;
// Merge and sort k arrays
static void merge_and_sort(int[] output, int[,] arr,
int n, int k)
{
// Put the elements in sorted array.
for (int i = 0; i < k; i++)
{
for (int j = 0; j < n; j++)
{
output[i * n + j] = arr[i,j];
}
}
// Sort the output array
Array.Sort(output);
}
// Driver code
static void Main()
{
// Input 2D-array
int[,] arr = { { 5, 7, 15, 18 },
{ 1, 8, 9, 17 },
{ 1, 4, 7, 7 } };
int n = N;
// Number of arrays
int k = arr.GetLength(0);
// Output array
int[] output = new int[n * k];
merge_and_sort(output, arr, n, k);
// Print merged array
for (int i = 0; i < n * k; i++)
Console.Write(output[i] + " ");
}
}
// This code is contributed by divyeshrabadiya07
Javascript
C++
// C++ program to merge K
// sorted arrays
#include
#define n 4
using namespace std;
// Function to perform merge operation
void merge(int l, int r, int* output)
{
// to store the starting point
// of left and right array
int l_in = l * n, r_in
= ((l + r) / 2 + 1) * n;
// To store the size of left and
// right array
int l_c = ((l + r) / 2 - l + 1) * n;
int r_c = (r - (l + r) / 2) * n;
// array to temporarily store left
// and right array
int l_arr[l_c], r_arr[r_c];
// storing data in left array
for (int i = 0; i < l_c; i++)
l_arr[i] = output[l_in + i];
// storing data in right array
for (int i = 0; i < r_c; i++)
r_arr[i] = output[r_in + i];
// to store the current index of
// temporary left and right array
int l_curr = 0, r_curr = 0;
// to store the current index
// for output array
int in = l_in;
// two pointer merge for
// two sorted arrays
while (
l_curr + r_curr < l_c + r_c) {
if (
r_curr == r_c
|| (l_curr != l_c
&& l_arr[l_curr] < r_arr[r_curr]))
output[in]
= l_arr[l_curr],
l_curr++, in++;
else
output[in]
= r_arr[r_curr],
r_curr++, in++;
}
}
// Code to drive merge-sort and
// create recursion tree
void divide(int l, int r, int* output,
int arr[][n])
{
if (l == r) {
/* base step to initialize the output
array before performing merge
operation */
for (int i = 0; i < n; i++)
output[l * n + i] = arr[l][i];
return;
}
// To sort left half
divide(l, (l + r) / 2,
output, arr);
// To sort right half
divide((l + r) / 2 + 1, r,
output, arr);
// Merge the left and right half
merge(l, r, output);
}
// Driver Function
int main()
{
// input 2D-array
int arr[][n] = { { 5, 7, 15, 18 },
{ 1, 8, 9, 17 },
{ 1, 4, 7, 7 } };
// Number of arrays
int k = sizeof(arr) / sizeof(arr[0]);
// Output array
int* output = new int[n * k];
divide(0, k - 1, output, arr);
// Print merged array
for (int i = 0; i < n * k; i++)
cout << output[i] << " ";
return 0;
}
Java
// Java program to merge
// K sorted arrays
import java.util.*;
class GFG {
static int n = 4;
// Function to perform
// merge operation
static void merge(
int l, int r, int[] output)
{
// To store the starting point
// of left and right array
int l_in = l * n, r_in
= ((l + r) / 2 + 1) * n;
// to store the size of left and
// right array
int l_c = ((l + r) / 2 - l + 1) * n;
int r_c = (r - (l + r) / 2) * n;
// array to temporarily store left
// and right array
int l_arr[] = new int[l_c],
r_arr[] = new int[r_c];
// storing data in left array
for (int i = 0; i < l_c; i++)
l_arr[i] = output[l_in + i];
// storing data in right array
for (int i = 0; i < r_c; i++)
r_arr[i] = output[r_in + i];
// to store the current index of
// temporary left and right array
int l_curr = 0, r_curr = 0;
// to store the current index
// for output array
int in = l_in;
// two pointer merge for two sorted arrays
while (l_curr + r_curr < l_c + r_c) {
if (
r_curr == r_c
|| (l_curr != l_c
&& l_arr[l_curr] < r_arr[r_curr])) {
output[in] = l_arr[l_curr];
l_curr++;
in++;
}
else {
output[in] = r_arr[r_curr];
r_curr++;
in++;
}
}
}
// Code to drive merge-sort and
// create recursion tree
static void divide(int l, int r, int[] output,
int arr[][])
{
if (l == r) {
/* base step to initialize the output
array before performing merge
operation */
for (int i = 0; i < n; i++)
output[l * n + i] = arr[l][i];
return;
}
// to sort left half
divide(l, (l + r) / 2, output, arr);
// to sort right half
divide((l + r) / 2 + 1, r, output, arr);
// merge the left and right half
merge(l, r, output);
}
// Driver Code
public static void main(String[] args)
{
// input 2D-array
int arr[][] = { { 5, 7, 15, 18 },
{ 1, 8, 9, 17 },
{ 1, 4, 7, 7 } };
// Number of arrays
int k = arr.length;
// Output array
int[] output = new int[n * k];
divide(0, k - 1, output, arr);
// Print merged array
for (int i = 0; i < n * k; i++)
System.out.print(output[i] + " ");
}
}
/* This code contributed by PrinciRaj1992 */
Python3
# Python3 program to merge K sorted arrays
n = 4 ;
# Function to perform merge operation
def merge(l, r, output) :
# to store the starting point of
# left and right array
l_in = l * n ;
r_in = ((l + r) // 2 + 1) * n;
# to store the size of left and
# right array
l_c = ((l + r) // 2 - l + 1) * n;
r_c = (r - (l + r) // 2) * n;
# array to temporarily store left
# and right array
l_arr = [0] * l_c; r_arr = [0] * r_c;
# storing data in left array
for i in range(l_c) :
l_arr[i] = output[l_in + i];
# storing data in right array
for i in range(r_c) :
r_arr[i] = output[r_in + i];
# to store the current index of
# temporary left and right array
l_curr = 0 ; r_curr = 0;
# to store the current index
# for output array
in1 = l_in;
# two pointer merge for two sorted arrays
while (l_curr + r_curr < l_c + r_c) :
if (r_curr == r_c or (l_curr != l_c and
l_arr[l_curr] < r_arr[r_curr])) :
output[in1] = l_arr[l_curr];
l_curr += 1; in1 += 1;
else :
output[in1] = r_arr[r_curr];
r_curr += 1; in1 += 1;
# Code to drive merge-sort and
# create recursion tree
def divide(l, r, output, arr) :
if (l == r) :
# base step to initialize the output
# array before performing merge
# operation
for i in range(n) :
output[l * n + i] = arr[l][i];
return;
# to sort left half
divide(l, (l + r) // 2, output, arr);
# to sort right half
divide((l + r) // 2 + 1, r, output, arr);
# merge the left and right half
merge(l, r, output);
# Driver code
if __name__ == "__main__" :
# input 2D-array
arr = [[ 5, 7, 15, 18 ],
[ 1, 8, 9, 17 ],
[ 1, 4, 7, 7 ]];
# Number of arrays
k = len(arr);
# Output array
output = [0] * (n * k);
divide(0, k - 1, output, arr);
# Print merged array
for i in range(n * k) :
print(output[i], end = " ");
# This code is contributed by Ryuga
C#
// C# program to merge K sorted arrays
using System;
class GFG {
static int n = 4;
// Function to perform merge operation
static void merge(int l, int r, int[] output)
{
// to store the starting point of left
// and right array
int l_in = l * n, r_in = ((l + r) / 2 + 1) * n;
// to store the size of left and
// right array
int l_c = ((l + r) / 2 - l + 1) * n;
int r_c = (r - (l + r) / 2) * n;
// array to temporarily store left
// and right array
int[] l_arr = new int[l_c];
int[] r_arr = new int[r_c];
// storing data in left array
for (int i = 0; i < l_c; i++)
l_arr[i] = output[l_in + i];
// storing data in right array
for (int i = 0; i < r_c; i++)
r_arr[i] = output[r_in + i];
// to store the current index of
// temporary left and right array
int l_curr = 0, r_curr = 0;
// to store the current index
// for output array
int index = l_in;
// two pointer merge for two sorted arrays
while (l_curr + r_curr < l_c + r_c) {
if (r_curr == r_c || (l_curr != l_c && l_arr[l_curr] < r_arr[r_curr])) {
output[index] = l_arr[l_curr];
l_curr++;
index++;
}
else {
output[index] = r_arr[r_curr];
r_curr++;
index++;
}
}
}
// Code to drive merge-sort and
// create recursion tree
static void divide(int l, int r, int[] output,
int[, ] arr)
{
if (l == r) {
/* base step to initialize the output
array before performing merge
operation */
for (int i = 0; i < n; i++)
output[l * n + i] = arr[l, i];
return;
}
// to sort left half
divide(l, (l + r) / 2, output, arr);
// to sort right half
divide((l + r) / 2 + 1, r, output, arr);
// merge the left and right half
merge(l, r, output);
}
// Driver Code
public static void Main(String[] args)
{
// input 2D-array
int[, ] arr = { { 5, 7, 15, 18 },
{ 1, 8, 9, 17 },
{ 1, 4, 7, 7 } };
// Number of arrays
int k = arr.GetLength(0);
// Output array
int[] output = new int[n * k];
divide(0, k - 1, output, arr);
// Print merged array
for (int i = 0; i < n * k; i++)
Console.Write(output[i] + " ");
}
}
// This code has been contributed by 29AjayKumar
PHP
Javascript
输出:
1 1 4 5 7 7 7 8 9 15 17 18
复杂度分析:
- 时间复杂度: O(N*k*log(N*k))。
所有元素的大小都是 n*k,所以时间复杂度是 O(N*k * log(N*k)) - 空间复杂度: O(N*k)。
存储输出数组需要 O(N*k) 空间。
有效的解决方案:
方法:一旦我们开始将k 个数组视为合并排序算法的中间状态,这个想法就变得清晰了。
由于已经排序了 k 个数组,因此合并 k 个数组。创建一个递归函数,它将接受 k 个数组并将它们分成两部分,并以每一半递归调用该函数。基本情况是当 k 的值小于 3 时。
请参阅本文以在 O(n) 时间内合并两个数组。
算法:
- 初始化大小为N*k的输出数组。
- 调用函数divide。让和表示要合并的数组范围,因此在0 到 k-1之间变化。
- 在每一步,我们递归地调用范围的左半部分和右半部分,以便将它们排序并存储在输出数组中。
- 之后,我们合并左半部分和右半部分。为了合并,我们需要确定输出数组中左右半部分的索引范围。我们可以很容易地找到。
- 左侧部分将从输出数组的索引l * n开始。
- 同样,右侧部分将从输出数组的索引((l + r) / 2 + 1) * n 开始。
C++
// C++ program to merge K
// sorted arrays
#include
#define n 4
using namespace std;
// Function to perform merge operation
void merge(int l, int r, int* output)
{
// to store the starting point
// of left and right array
int l_in = l * n, r_in
= ((l + r) / 2 + 1) * n;
// To store the size of left and
// right array
int l_c = ((l + r) / 2 - l + 1) * n;
int r_c = (r - (l + r) / 2) * n;
// array to temporarily store left
// and right array
int l_arr[l_c], r_arr[r_c];
// storing data in left array
for (int i = 0; i < l_c; i++)
l_arr[i] = output[l_in + i];
// storing data in right array
for (int i = 0; i < r_c; i++)
r_arr[i] = output[r_in + i];
// to store the current index of
// temporary left and right array
int l_curr = 0, r_curr = 0;
// to store the current index
// for output array
int in = l_in;
// two pointer merge for
// two sorted arrays
while (
l_curr + r_curr < l_c + r_c) {
if (
r_curr == r_c
|| (l_curr != l_c
&& l_arr[l_curr] < r_arr[r_curr]))
output[in]
= l_arr[l_curr],
l_curr++, in++;
else
output[in]
= r_arr[r_curr],
r_curr++, in++;
}
}
// Code to drive merge-sort and
// create recursion tree
void divide(int l, int r, int* output,
int arr[][n])
{
if (l == r) {
/* base step to initialize the output
array before performing merge
operation */
for (int i = 0; i < n; i++)
output[l * n + i] = arr[l][i];
return;
}
// To sort left half
divide(l, (l + r) / 2,
output, arr);
// To sort right half
divide((l + r) / 2 + 1, r,
output, arr);
// Merge the left and right half
merge(l, r, output);
}
// Driver Function
int main()
{
// input 2D-array
int arr[][n] = { { 5, 7, 15, 18 },
{ 1, 8, 9, 17 },
{ 1, 4, 7, 7 } };
// Number of arrays
int k = sizeof(arr) / sizeof(arr[0]);
// Output array
int* output = new int[n * k];
divide(0, k - 1, output, arr);
// Print merged array
for (int i = 0; i < n * k; i++)
cout << output[i] << " ";
return 0;
}
Java
// Java program to merge
// K sorted arrays
import java.util.*;
class GFG {
static int n = 4;
// Function to perform
// merge operation
static void merge(
int l, int r, int[] output)
{
// To store the starting point
// of left and right array
int l_in = l * n, r_in
= ((l + r) / 2 + 1) * n;
// to store the size of left and
// right array
int l_c = ((l + r) / 2 - l + 1) * n;
int r_c = (r - (l + r) / 2) * n;
// array to temporarily store left
// and right array
int l_arr[] = new int[l_c],
r_arr[] = new int[r_c];
// storing data in left array
for (int i = 0; i < l_c; i++)
l_arr[i] = output[l_in + i];
// storing data in right array
for (int i = 0; i < r_c; i++)
r_arr[i] = output[r_in + i];
// to store the current index of
// temporary left and right array
int l_curr = 0, r_curr = 0;
// to store the current index
// for output array
int in = l_in;
// two pointer merge for two sorted arrays
while (l_curr + r_curr < l_c + r_c) {
if (
r_curr == r_c
|| (l_curr != l_c
&& l_arr[l_curr] < r_arr[r_curr])) {
output[in] = l_arr[l_curr];
l_curr++;
in++;
}
else {
output[in] = r_arr[r_curr];
r_curr++;
in++;
}
}
}
// Code to drive merge-sort and
// create recursion tree
static void divide(int l, int r, int[] output,
int arr[][])
{
if (l == r) {
/* base step to initialize the output
array before performing merge
operation */
for (int i = 0; i < n; i++)
output[l * n + i] = arr[l][i];
return;
}
// to sort left half
divide(l, (l + r) / 2, output, arr);
// to sort right half
divide((l + r) / 2 + 1, r, output, arr);
// merge the left and right half
merge(l, r, output);
}
// Driver Code
public static void main(String[] args)
{
// input 2D-array
int arr[][] = { { 5, 7, 15, 18 },
{ 1, 8, 9, 17 },
{ 1, 4, 7, 7 } };
// Number of arrays
int k = arr.length;
// Output array
int[] output = new int[n * k];
divide(0, k - 1, output, arr);
// Print merged array
for (int i = 0; i < n * k; i++)
System.out.print(output[i] + " ");
}
}
/* This code contributed by PrinciRaj1992 */
蟒蛇3
# Python3 program to merge K sorted arrays
n = 4 ;
# Function to perform merge operation
def merge(l, r, output) :
# to store the starting point of
# left and right array
l_in = l * n ;
r_in = ((l + r) // 2 + 1) * n;
# to store the size of left and
# right array
l_c = ((l + r) // 2 - l + 1) * n;
r_c = (r - (l + r) // 2) * n;
# array to temporarily store left
# and right array
l_arr = [0] * l_c; r_arr = [0] * r_c;
# storing data in left array
for i in range(l_c) :
l_arr[i] = output[l_in + i];
# storing data in right array
for i in range(r_c) :
r_arr[i] = output[r_in + i];
# to store the current index of
# temporary left and right array
l_curr = 0 ; r_curr = 0;
# to store the current index
# for output array
in1 = l_in;
# two pointer merge for two sorted arrays
while (l_curr + r_curr < l_c + r_c) :
if (r_curr == r_c or (l_curr != l_c and
l_arr[l_curr] < r_arr[r_curr])) :
output[in1] = l_arr[l_curr];
l_curr += 1; in1 += 1;
else :
output[in1] = r_arr[r_curr];
r_curr += 1; in1 += 1;
# Code to drive merge-sort and
# create recursion tree
def divide(l, r, output, arr) :
if (l == r) :
# base step to initialize the output
# array before performing merge
# operation
for i in range(n) :
output[l * n + i] = arr[l][i];
return;
# to sort left half
divide(l, (l + r) // 2, output, arr);
# to sort right half
divide((l + r) // 2 + 1, r, output, arr);
# merge the left and right half
merge(l, r, output);
# Driver code
if __name__ == "__main__" :
# input 2D-array
arr = [[ 5, 7, 15, 18 ],
[ 1, 8, 9, 17 ],
[ 1, 4, 7, 7 ]];
# Number of arrays
k = len(arr);
# Output array
output = [0] * (n * k);
divide(0, k - 1, output, arr);
# Print merged array
for i in range(n * k) :
print(output[i], end = " ");
# This code is contributed by Ryuga
C#
// C# program to merge K sorted arrays
using System;
class GFG {
static int n = 4;
// Function to perform merge operation
static void merge(int l, int r, int[] output)
{
// to store the starting point of left
// and right array
int l_in = l * n, r_in = ((l + r) / 2 + 1) * n;
// to store the size of left and
// right array
int l_c = ((l + r) / 2 - l + 1) * n;
int r_c = (r - (l + r) / 2) * n;
// array to temporarily store left
// and right array
int[] l_arr = new int[l_c];
int[] r_arr = new int[r_c];
// storing data in left array
for (int i = 0; i < l_c; i++)
l_arr[i] = output[l_in + i];
// storing data in right array
for (int i = 0; i < r_c; i++)
r_arr[i] = output[r_in + i];
// to store the current index of
// temporary left and right array
int l_curr = 0, r_curr = 0;
// to store the current index
// for output array
int index = l_in;
// two pointer merge for two sorted arrays
while (l_curr + r_curr < l_c + r_c) {
if (r_curr == r_c || (l_curr != l_c && l_arr[l_curr] < r_arr[r_curr])) {
output[index] = l_arr[l_curr];
l_curr++;
index++;
}
else {
output[index] = r_arr[r_curr];
r_curr++;
index++;
}
}
}
// Code to drive merge-sort and
// create recursion tree
static void divide(int l, int r, int[] output,
int[, ] arr)
{
if (l == r) {
/* base step to initialize the output
array before performing merge
operation */
for (int i = 0; i < n; i++)
output[l * n + i] = arr[l, i];
return;
}
// to sort left half
divide(l, (l + r) / 2, output, arr);
// to sort right half
divide((l + r) / 2 + 1, r, output, arr);
// merge the left and right half
merge(l, r, output);
}
// Driver Code
public static void Main(String[] args)
{
// input 2D-array
int[, ] arr = { { 5, 7, 15, 18 },
{ 1, 8, 9, 17 },
{ 1, 4, 7, 7 } };
// Number of arrays
int k = arr.GetLength(0);
// Output array
int[] output = new int[n * k];
divide(0, k - 1, output, arr);
// Print merged array
for (int i = 0; i < n * k; i++)
Console.Write(output[i] + " ");
}
}
// This code has been contributed by 29AjayKumar
PHP
Javascript
输出:
1 1 4 5 7 7 7 8 9 15 17 18
复杂度分析:
- 时间复杂度: O(N*k*log(k))。
在每一层中,大小为 N*k 的数组被遍历一次,层数为 log(k)。 - 空间复杂度: O(N*k)。
存储输出数组需要 O(N*k) 空间。
我们也可以通过使用 min-heap 来解决这个问题。
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。