基本思想
归并排序是将两个或两个以上的有序表组合成一个新的有序表。
假设初始序列有n个记录,则可看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到
⌈n2⌉
⌈
n
2
⌉
个长度为2或1的有序子序列;再两两归并,……,如此重复,直至得到一个长度为n的有序序列为止,这种排序方法称为2-路归并排序。
实现快速排序的步骤
递归实现
1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置
3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
4. 重复步骤3直到某一指针到达序列尾
5. 将另一序列剩下的所有元素直接复制到合并序列尾
6. 将最终结果写回原数组
Tips:递归形式的算法在形式上较简洁,但实用性很差。
C++实现
void Merge(int arr[], int arrDst[], int iStart, int iEnd)
{
if (iStart >= iEnd)
return;
int iMid = iStart + ((iEnd - iStart) >> 1);
// 设定两个指针,最初位置分别为两个已经排序序列的起始位置
int iStart1 = iStart, iEnd1 = iMid;
int iStart2 = iMid + 1, iEnd2 = iEnd;
Merge(arr, arrDst, iStart1, iEnd1);
Merge(arr, arrDst, iStart2, iEnd2);
int iIndex = iStart;
// 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
while (iStart1 <= iEnd1 && iStart2 <= iEnd2)
arrDst[iIndex++] = arr[iStart1] < arr[iStart2] ? arr[iStart1++] : arr[iStart2++];
// 将另一序列剩下的所有元素直接复制到合并序列尾
while (iStart1 <= iEnd1)
arrDst[iIndex++] = arr[iStart1++];
while (iStart2 <= iEnd2)
arrDst[iIndex++] = arr[iStart2++];
// 将最终结果写回原数组
for (iIndex = iStart; iIndex <= iEnd; iIndex++)
arr[iIndex] = arrDst[iIndex];
}
void MergeSort(int arr[], const int iLength)
{
// 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
int *arrDst = new int[iLength];
Merge(arr, arrDst, 0, iLength - 1);
delete[]arrDst;
}
总结
与快速排序、堆排序相比,归并排序最大的特点是,它是一种稳定的排序方法。但在一般情况下,很少利用2-路归并排序法进行内部排序
时间复杂度
O(nlogn)
O
(
n
l
o
g
n
)
空间复杂度
实现归并排序需要和待排记录等数量的辅助空间。
最坏时间复杂度 | 最优时间复杂度 | 平均时间复杂度 | 空间复杂度 |
---|---|---|---|
O(nlogn) O ( n l o g n ) | O(n) O ( n ) | O(nlogn) O ( n l o g n ) | O(n) O ( n ) |