将待排序的元素序列分成两个长度相等的子序列,为每个子序列排序,然后再将它们合并成一个序列。合并两个子序列的过程称为两路归并,核心操作是将一维数组中前后相邻的两个有序序列归并为一个有序序列。
一次2-路归并排序的算法:
//一次归并排序算法,k为子序列长度,n为数组长度
void Merge(int * pArry, int *pTemp, int k, int n)
{
int i1, i2, l1, r1, l2, r2, j; //l1、r1分别指向第一子序列的首尾
l1= 0; //l2、r2分别指向第二个子序列的首尾
j = 0;
while (l1 + k < n)
{
l2 = l1 + k;
r1 = l2 - 1;
r2 = (l2 + k - 1 <= n - 1) ? l2 + k - 1 : n - 1;
for (i1 = l1, i2 = l2; i1 <= r1 && i2 <= r2; j++)
{
if (pArry[i1] <= pArry[i2])
{
pTemp[j] = pArry[i1++];
}
else
{
pTemp[j] = pArry[i2++];
}
}
while (i1 <= r1) //序列2已归并完,将序列1的剩余元素顺序放入数组中
{
pTemp[j++] = pArry[i1++];
}
while (i2 <= r2) //序列1已归并完,将序列2的剩余元素顺序放入数组中
{
pTemp[j++] = pArry[i2++];
}
l1 = r2 + 1; //从前向后继续进行
}
for (i1 = l1; i1 < n;i1++, j++) //将原始序列中剩余不足一组的元素顺序放到数组中
{
pTemp[j] = pArry[i1];
}
}
void MergeSort(int * pArry, int len)
{
int j;
int *pTemp = new int[len];
for (int i = 1; i < len; i *= 2) //每循环一次,子序列长度增加一倍
{
Merge(pArry, pTemp, i, len);
for (j = 0; j < len; j++)
{
pArry[j] = pTemp[j];
}
}
delete [] pTemp;
}
2-路归并排序是稳定的,算法的效率和快速排序是同一数量级的,时间复杂度为O(nlog2(n))。但是需要与原始数组一样大小的辅助空间,占用较大存储空间。