导读:
我们在前面学习了排序,包括直接插入排序,希尔排序,选择排序,堆排序,冒泡排序和快排。
今天我们来讲一讲归并排序和计数排序。
关注博主或是订阅专栏,掌握第一消息。
1. 归并排序
1.1 基本思想
归并排序的基本思想是将待排序的数组分成两个较小的子数组,然后递归地对这两个子数组进行排序,最后将两个有序的子数组合并成一个有序的数组。
- 将待排序数组分成两个较小的子数组,直到子数组中只剩下一个元素。
- 对两个子数组分别进行归并排序,即递归调用归并排序函数。
- 将两个有序的子数组进行合并,得到一个有序的数组。合并过程中,从两个子数组的第一个元素开始,依次比较大小,将较小的元素放入新的数组中。
- 将合并得到的有序数组返回。
归并排序的关键在于合并两个有序的子数组,这一步可以使用辅助数组来存储合并的结果。合并时,可以使用两个指针分别指向两个子数组的起始位置,比较指针指向的元素的大小,将较小的元素放入新的数组中,并将对应指针后移一位。当一个子数组遍历完后,将另一个子数组剩余的元素直接放入新的数组中即可。
1.2 递归实现
非递归实现归并排序的思想是通过迭代和循环来分割和合并数组,而不使用递归。
- 初始化一个辅助数组,用于存储合并的结果。
- 从数组的起始位置开始,将数组中的每个元素看作一个独立的有序序列,将它们分别放入辅助数组。
- 设置一个变量gap,初始值为1,代表每次合并的有序子序列的长度。
- 进入循环,循环条件是gap小于数组的长度。
- 在每一次循环中,将两个有序子序列合并并放入辅助数组中。
- 将合并得到的有序子序列放回原数组的对应位置。
- 将gap的值加倍,继续下一轮循环,直到gap大于或等于数组的长度
通过不断合并较小的有序子序列,直到整个数组排序完成,即可得到最终的有序数组。非递归实现归并排序的好处是减少了函数调用的开销,提高了排序的效率。
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&