先声明:所有的排序我都会总结记录在博客里,最后会有一个大的cpp文件包含全部排序的代码,每个排序算法放在单独的一个namespace里面,清晰明了,并设计对数器给出测试。我会把它放到网盘供需要之人下载,见这里。 ps:所有的排序以升序为基准。测试编译器为Visual C++
归并排序思想:将原数组拆成前后两半,递归地对前半部分和后半部分分别执行排序过程,再将排好序的前后两部分合并。
典型的分治问题,而分治一般用递归去解。
归并排序也是基于比较的排序。
归并排序稳定。
代码:
template<typename T>
void merge(T* arr, int l, int m, int r, T* aux_arr) { // merge函数:合并两个有序数组
int k = m + 1;
int tmp = l;
int numElements = r - l + 1;
while (l <= m && k <= r) {
if (arr[l] <= arr[k]) {
aux_arr[tmp++] = arr[l++];
}
else {
aux_arr[tmp++] = arr[k++];
}
}
while (l <= m) {
aux_arr[tmp++] = arr[l++];
}
while (k <= r) {
aux_arr[tmp++] = arr[k++];
}
//copy aux_arr back
for (int i = 0; i < numElements; ++i, r--) {
arr[r] = aux_arr[r];
}
}
template<typename T>
void mergesortDrive(T* arr, int l, int r, T* aux_arr) {
if (r <= l)
return;
int m = l + ((r - l) >> 1);
mergesortDrive(arr, l, m, aux_arr); //记得本科老师说:归并是先享福,后吃苦
mergesortDrive(arr, m + 1, r, aux_arr); //好像有那么点儿味道。 快排是先吃苦后享福
merge(arr, l, m, r, aux_arr); //把两个排好序的数组合并
}
//mergesort主程序
template<typename T>
void mergesort(T* arr, size_t size) {
if (size <= 0)
return;
T* aux_arr = new T[size]; //归并排序需要一个辅助数组
mergesortDrive(arr, 0, size - 1, aux_arr);
delete[] aux_arr;
}
贴一张图:来自《数据结构与算法分析》一书。
时间复杂度:分治问题,写出递归公式,求解即可。
递归公式:T(N) = 2T(N/2) + O(N)
时间复杂度为O(NlogN),空间复杂度为O(N),(用了一个辅助数组O(N),还有递归调用的函数栈空间logN )。
结果:
纸上得来终觉浅,绝知此事要躬行。