单个元素肯定有序;
归并排序采用分治思想,分而治之:
将待排序数组划分为n等分,每份长度为1个元素,则 n份全部有序;
再一生二,二生四,逐步两两元素有序的区间,归一合并成1个有序区间;
最终会归并出整一个数组元素有序的结果.
归并排序有两种实现方式:
(1)自顶向下递归调用实现;
(2)自底向上迭代执行实现.
//左右双闭区间[low,high];
//归并过程;
template<typename T>
void __Merge(T* arr, T* tempArr, const int low, const int mid, const int high) {
//临时存储空间需要在每一次归并之前更新数据,使得已排序的元素得以存储;
for (int index = low; index <= high; ++index) {
tempArr[index] = arr[index];
}
int i = low;//左区间[low,mid]起点;
int j = mid + 1;//右区间[mid+1,high]起点;
//归并过程,使用索引k记录已排好序的最后元素位置;
for (int k = low; k <= high; ++k) {
if (i > mid) {//左区间已遍历完;
arr[k] = tempArr[j++];
}
else if (j > high) {//右区间已遍历完;
arr[k] = tempArr[i++];
}
else if (tempArr[i] <= tempArr[j]) {//相等时取左侧元素以保持排序的稳定性;
arr[k] = tempArr[i++];
}
else {//左大右小时,才取右区间元素;
arr[k] = tempArr[j++];
}
////输出并理解中间过程;
//RandomArrayFuntionHelper::PrintArray(arr, low, high+1);
//RandomArrayFuntionHelper::PrintArray(tempArr, low, high+1);
//std::cout << " ------\n";
}
}
//分治过程;
template<typename T>
void __MergeSort(T* arr, T* tempArr, int low, int high) {//左闭右开区间,[low,high);
//if (low < high) {
//通过修改条件并通过else代码,使用直接插入排序优化;
if (low + 15 < high) {
//int mid = low + (high - low) / 2;
int mid = low + ((high - low) >> 1);
//分(二分、折半);
__MergeSort(arr, tempArr, low, mid);
__MergeSort(arr, tempArr, mid + 1, high);
//治(归并、合一);
if (arr[mid] > arr[mid + 1]) {
__Merge(arr, tempArr, low, mid, high);
//下一行代码为适得其反的优化,https://blog.csdn.net/tinyDolphin/article/details/78457343;
//__Merge(tempArr, arr, low, mid, high);
}
}
else {
DirectInsertionSort(arr, low, high);
//BinaryInsertSort(arr, low, high);
//经测试,百万数量级时:剩余 10~50 元素左右时使用,效果较佳(治在if优化之前15最佳,加了if条件之后50最好);
//千万数量级时:剩余 30 元素左右时使用,效果较佳;
//二分插入的优化比直接插入的优化稍微逊色,也可以适当使剩余元素变为最佳状态时的 3/2倍左右,二分的效果更佳;
}
}
//递归调用(Top-down);
template<typename T>
//void DataSort::MergeSortTD(T* arr, const std::size_t n) {
void MergeSortTD(T* arr, const std::size_t n) {
//临时数组空间;
T *tempArr = new T[n];
//仅处理元素索引区间(相当于左右全闭区间);
__MergeSort(arr, tempArr, 0, n - 1);
delete[] tempArr;
}
温馨提示:
代码中间采用了小规模时,直接通过直接插入排序算法实现优化;
该部分代码链接在我的另外一篇文章里,链接如下:
插入排序(重温经典算法系列)
//重载直接插入排序;
template <typename T>
void DirectInsertionSort(T* arr, const int low, const int high) {//high极可能会传入负数值,故而不可使用无符号数;
assert(arr);
//i索引遍历待排序元素;
for (int i = low + 1; i <= high; ++i) {
T temp = arr[i];
int j;
for (j = i; j > low && arr[j - 1] > temp; --j) {
arr[j] = arr[j - 1];//把前边的元素往后挪,用这一操作替换掉每一次的数值交换swap,能减少开销;
}
//找到合适插入位置j,第二次循环提前终止;
if (j != i) {
arr[j] = temp;
}
}
}
关于归并排序算法的具体优化思想,可以参考文章:
归并排序及其优化
需要使用头文件:
#include
//归并过程;
template<typename T>
void __Merge(T* arr, T* tempArr, const int low, const int mid, const int high) {
//临时存储空间需要在每一次归并之前更新数据,使得已排序的元素得以存储;
for (int index = low; index <= high; ++index) {
tempArr[index] = arr[index];
}
int i = low;//左区间[low,mid]起点;
int j = mid + 1;//右区间[mid+1,high]起点;
//归并过程,使用索引k记录已排好序的最后元素位置;
for (int k = low; k <= high; ++k) {
if (i > mid) {//左区间已遍历完;
arr[k] = tempArr[j++];
}
else if (j > high) {//右区间已遍历完;
arr[k] = tempArr[i++];
}
else if (tempArr[i] <= tempArr[j]) {//相等时取左侧元素以保持排序的稳定性;
arr[k] = tempArr[i++];
}
else {//左大右小时,才取右区间元素;
arr[k] = tempArr[j++];
}
////输出并理解中间过程;
//RandomArrayFuntionHelper::PrintArray(arr, low, high+1);
//RandomArrayFuntionHelper::PrintArray(tempArr, low, high+1);
//std::cout << " ------\n";
}
}
//归并排序(自底向上迭代版)(Bottom-up);
template<typename T>
//void DataSort::MergeSortBU(T* arr, const std::size_t n) {
void MergeSortBU(T* arr, const std::size_t n) {
T* tempArr = new T[n];
//最开始的小规模数组,使用直接插入排序优化;
const std::size_t littleSize = 16;
for (std::size_t index = 0; index < n; index += littleSize) {
DirectInsertionSort(arr, index, std::min(index + littleSize - 1, n - 1));
}
//第 i ( i = 0,1,2 …… )轮要归并已分别各自有序的两个数组范围是;
//arr[ index + i * sz, index + (i+1) * sz - 1];
//arr[ index + (i+1) * sz, index + (i+2) * sz - 1];
for (std::size_t sz = littleSize; sz < n; sz += sz) {//分组长度size(元素个数);
for (std::size_t index = 0; index + sz < n; index += sz + sz) {
if (arr[index + sz - 1] > arr[index + sz]) {
__Merge(arr, tempArr, index, index + sz - 1, std::min(index + sz + sz - 1, n - 1));
}
}
}
delete[] tempArr;
}
归并排序优化思想解说,可以参考:
归并排序及其优化
归并排序算法的动画过程演示,可以参考:
排序算法过程演示
交流方式
QQ —— 2636105163(南国烂柯者)
温馨提示:
转载请注明出处!!