🚩概念:
归并排序,是创建在归并操作上的一种有效的排序算法。算法是采用分治法(Divide and Conquer)的一个非常典型的应用,且各层分治递归可以同时进行。归并排序思路简单,速度仅次于快速排序,为稳定排序算法,一般用于对总体无序,但是各子项相对有序的数列。
一:⛲递归实现
🌟算法思路
归并排序是用分治思想,分治模式在每一层递归上有三个步骤:
- 分解(Divide):将n个元素分成个含n/2个元素的子序列。
- 解决(Conquer):用合并排序法对两个子序列递归的排序。
- 合并(Combine):合并两个已排序的子序列已得到排序结果。
该算法需要先将数组分解,直到每个子序列为一个元素,再将子序列两两合并排序,思路可以参考二叉树的后序递归
⚡复杂度
平均时间复杂度:O(nlogn)
最佳时间复杂度:O(n)
最差时间复杂度:O(nlogn)
空间复杂度:O(n)
⚡性能
速度仅次于快速排序。
⚡稳定性
稳定排序
⚡动图展示:
💬源码如下:
void _MergeSort(int* a, int begin, int end, int* tmp)
{
if (begin >= end)
return;
//分解
int mid = (begin + end) / 2;
_MergeSort(a, begin, mid, tmp);
_MergeSort(a, mid+1, end, tmp);
// 归并
int begin1 = begin, end1 = mid;
int begin2 = mid + 1, end2 = end;
int i = begin;
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] < a[begin2])
{
tmp[i++] = a[begin1++];
}
else
{
tmp[i++] = a[begin2++];
}
}
while(begin1 <= end1)
{
tmp[i++] = a[begin1++];
}
while (begin2 <= end2)
{
tmp[i++] = a[begin2++];
}
memcpy(a + begin, tmp + begin, sizeof(int) * (end - begin + 1));
}
void MergeSort(int* a, int n)
{
int* tmp = (int*)malloc(sizeof(int) * n);
if (tmp == NULL)
{
perror("malloc fail");
return;
}
_MergeSort(a, 0, n - 1, tmp);
free(tmp);
}
二:⛲非递归实现
🌟算法思路:
归并排序的递归实现是先将数组分解,直到每个子序列只有一个元素,在将子序列两两归并,非递归的实现思路则没有了分解的过程,直接将数组元素一个与一个归并,在两个与两个归并,在四个与四个归并.......,直到最后两组归并,数组变为有序数组
🚩实现过程:
1.⚡归并过程
gap初始化为1,每归并完一轮,gap×2(一一归并,二二归并,四四归并.........)
当gap=1,让下标为0和1的两组归并为一组,让下表为2和3的两组归并为一组..........
当gap=2,让下标为0 1和2 3的两组归并为一组,让下表为4 5和6 7的两组归并为一 组..........
当gap等于2的i次方,数组被分为两组,这两组归并完数组就排序好了
注意当每一轮归并中的每两组归并完后,要归并下两组,i要加2×gap,因为每一小组元素为 gap个文章来源:https://www.toymoban.com/news/detail-807941.html
2.⚡边界控制
由于gap一直为2^i次方,所以当待排序数组的元素个数不为2^i次方时,我们默认设置的end1或begin2或end2可能会越界,所以每次进行归并时需要对他们进行控制文章来源地址https://www.toymoban.com/news/detail-807941.html
- 当end1越界时,说明和第一组归并的第二组就没有元素,就不需要归并操作,虽然end1越界了,但是第一组本身就是有序的,直接break跳出循环即可
- 当begin2越界时,说明和第一组归并的第二组就没有元素,就不需要归并操作,直接break跳出循环即可
- 当end2越界时,由于由于我们直到待排序数组的个数,自然知道end2的下标应该为n-1
💬代码如下:
void MergeSortNonR(int* a, int begin, int end)
{
int n = end - begin + 1;
int* tmp = (int*)malloc(sizeof(int) * (n));
if (tmp == NULL)
{
perror("malloc");
return;
}
int gap = 1;
//当gap小于n时两个组才都有元素,才需要归并
while (gap < n)
{
int j = 0;
for (size_t i = 0; i < n; i += 2 * gap)
{
int begin1 = i, end1 = i + gap - 1;
int begin2 = i + gap, end2 = i + 2 * gap - 1;
//边界管理
if (end1 >= n||begin2>=n)
{
break;
}
if (end2 >= n)
{
end2 = n - 1;
}
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] <= a[begin2])
{
tmp[j++] = a[begin1++];
}
else
{
tmp[j++] = a[begin2++];
}
}
while (begin1 <= end1)
{
tmp[j++] = a[begin1++];
}
while (begin2 <= end2)
{
tmp[j++] = a[begin2++];
}
//归并完后拷贝给原数组
memcpy(a + i, tmp + i, sizeof(int) * (end2 - i + 1));
}
gap *= 2;
}
free(tmp);
}
到了这里,关于[排序算法]:归并排序(Merge Sort)(递归与非递归实现详解)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!