目标
给定 2 个升序数组,将合并后的升序数组写入第 1 个数组。
假设
1、第 1 个数组的有足够的容量。
算法
类似于归并排序的归并过程。
同时从后往前遍历两个数组,将较大的元素放到第一个数组的相应位置,也就是合并后该有的位置。
正确性
作者不会证明,但测试结果表明,这个算法在某种程度上是可靠的。
时间复杂度
设第一个数组的长度为 n, 第二个数组的长度为 m。
最好 O(m),即第 2 个数组中所有元素都大于第 1 个数组最大的元素。
最坏 O(m+n),即第 2 个数组中所有元素都小于第 1 个数组最小的元素。
平均 O(m+n),平均需要计算 (m + n/2) 次。
核心代码
void merge(int a[], const int alen, const int b[], const int blen)
{
int ia = alen - 1;
int ib = blen - 1;
int imerged = alen + blen - 1;
while (ia >= 0 && ib >= 0)
{
if (a[ia] > b[ib])
{
a[imerged] = a[ia];
--ia;
}
else
{
a[imerged] = b[ib];
--ib;
}
--imerged;
}
while (ib >= 0)
{
a[imerged] = b[ib];
--imerged;
--ib;
}
}
测试代码
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <time.h>
void fprintArray(FILE* stream, const int arr[], const int len)
{
int i;
for (i = 0; i < len; ++i)
{
fprintf(stream, " %d", arr[i]);
}
}
int compare_int(const void *ptr_a, const void *ptr_b)
{
const int a = *(int*)ptr_a;
const int b = *(int*)ptr_b;
if (a > b)
return 1;
else if (b > a)
return -1;
else
return 0;
}
bool test_merge(FILE* log_stream)
{
// const int MAXLEN = 1e7;
#define MAXLEN ((int) 1e5)
static int a[MAXLEN << 1];
static int b[MAXLEN];
srand(time(NULL));
const int alen = rand() % MAXLEN + 1;
const int blen = rand() % MAXLEN + 1;
int i;
for (i = 0; i < alen; ++i)
{
a[i] = rand();
}
for (i = 0; i < blen; ++i)
{
b[i] = rand();
}
qsort(a, alen, sizeof(*a), compare_int);
qsort(b, blen, sizeof(*b), compare_int);
if (log_stream != NULL)
{
fprintf(log_stream, "a:");
fprintArray(log_stream, a, alen);
fputc('\n', log_stream);
fprintf(log_stream, "b:");
fprintArray(log_stream, b, blen);
fputc('\n', log_stream);
}
merge(a, alen, b, blen);
if (log_stream != NULL)
{
fprintf(log_stream, "merged:");
fprintArray(log_stream, a, alen + blen);
fputc('\n', log_stream);
}
for (i = 1; i < alen+blen; ++i)
{
if (a[i] < a[i-1])
{
return false;
}
}
return true;
#undef MAXLEN
}
int main()
{
const int NUM_TEST = 100;
FILE* log_stream = fopen("merge.log", "w");
int i;
int pass = 0;
int fail = 0;
for (i = 0; i < NUM_TEST; ++i)
{
if (test_merge(log_stream))
{
++pass;
}
else
{
++fail;
}
}
fclose(log_stream);
printf("total: %d, pass: %d, fail: %d, pass_rate: %lf%%\n", NUM_TEST, pass, fail, 100.0 * pass / NUM_TEST);
return 0;
}
泛化
#include <utility>
template<typename Type>
void merge(Type a[], const int alen, const Type b[], const int blen)
{
int ia = alen - 1;
int ib = blen - 1;
int imerged = alen + blen - 1;
while (ia >= 0 && ib >= 0)
{
if (a[ia] > b[ib])
{
a[imerged] = std::move(a[ia]);
--ia;
}
else
{
a[imerged] = b[ib];
--ib;
}
--imerged;
}
while (ib >= 0)
{
a[imerged] = b[ib];
--imerged;
--ib;
}
}