归并排序是一种最坏情况复杂度为O(nlgn)的排序算法,常用于要求进行稳定排序的应用中,STL中的stable_sort常见的实现便是采用了归并排序。但是归并排序在归并的过程中,需要额外O(n)的存储空间,且内循环平均效率劣于快速排序,所以对于一般不要求稳定性的排序,通常采用快速排序。
归并排序的原理
归并排序是分治算法的经典应用之一,即将一个大小为n的问题分解为两个大小为n/2的子问题,最后将子问题的解合并得到最终问题的解。可以写出主函数的代码:
void MergeSort(vector<int>&ToBeSorted,int first,int last){
if(first >= last) return;
int mid = first + ((last - first) >> 1);
MergeSort(ToBeSorted,first,mid);
MergeSort(ToBeSorted,mid + 1,last);
Merge(ToBeSorted,first,mid,last);
}
分治法分容易,难就难在如何分而治之,也就是Merge函数如何编写。我们知道Merge函数的作用是将两个已排序的数组合并为一个已排序的数组,即将ToBeSorted[first…mid]和ToBeSorted[mid+1…last]这俩已排序的数组合并为ToBeSorted[first…last]。这样就很容易写出Merge函数的代码了:
void Merge(vector<int>&ToBeSorted,int first,int mid,int last){
int lhsIndex = first,rhsIndex = mid + 1;
vector<int>tmp(ToBeSorted.begin()+first,ToBeSorted.begin()+last + 1);
for(int index = first;index != last;++index)
if(lhsIndex > mid) tmp[index] = ToBeSorted[rhsIndex++];
else if(rhsIndex > last) tmp[index] = ToBeSorted[lhsIndex++];
else if(ToBeSorted[lhsIndex] <= ToBeSorted[rhsIndex]) tmp[index] = ToBeSorted[lhsIndex++];
else tmp[index] = ToBeSorted[rhsIndex++];
copy(tmp.begin(),tmp.end(),ToBeSorted.begin() + first);
}
上述Merge的实现主要优点在于简洁,一个循环便实现了主逻辑以及所有的边界条件。缺点在于每次调用Merge函数时都需要生成一次临时数组,实际应用时可以将整个数组在排序前一起生成。