递归实现归并排序
归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
完成一个归并排序分两步:(1)将原序列不断二分,直到子序列长度为1,这时这个子序列一定有序;(2)向上归并:每次将两个已经有序的子序列归并成一个有序的序列。
实现归并函数的具体思路:
(1)我们需要另一个数组,用来存放已经排好序的子序列,且这数组最好用malloc开辟在堆上,防止函数结束时栈帧销毁,数组空间的使用权限被还给操作系统。
(2)这里使用递归的思路,将原数组从中间开始不断分,直到每一个子序列中只有一个元素,这时的子序列必定有序。定义一个begin和end,求得mid,将数组分为[begin,mid]和[mid+1,end]两个子序列,再对两个子序列分别重复上述过程。当degin>=end时,说明已经不能再分了,这时,每个子序列中只有一个元素。
虽然图画的好像有很多数组空间的样子,但其实只是用begin和end来控制数组的区间,并没有开其他数组空间。
(3)二路归并。就是每次让两个子序列进行归并。这时要用到tmp数组,把经过归并排序好的两个子序列的数据存起来,然后复制到a数组对应的位置,这样a数组中的部分实现有序。递归返回,重复以上步骤。
这样基本就完成了一个归并排序。
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;//i用来控制数据放入tmp的位置//由于数据要放在tmp中与a对应的位置,所以给i赋值为beginint i = begin;while (begin1 <= end1 && begin2 <= end2)//两个子序列都还有数据未比较{//选择两个子序列中较小的放入tmp中if (a[begin1] < a[begin2]){tmp[i++] = a[begin1++];}if (a[begin1] >= a[begin2]){tmp[i++] = a[begin2++];}}//子序列1没排完,把剩余的都按顺序放入tmp中while (begin1 <= end1){tmp[i++] = a[begin1++];}//子序列2没排完,把剩余的都按顺序放入tmp中while (begin2 <= end2){tmp[i++] = a[begin2++];}//将在tmp中以排好的元素复制回a数组中memcpy(a + begin, tmp + begin, sizeof(int) * (end - begin + 1));
}//归并排序
void MergeSort(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);//申请和a相同大小的空间if (tmp == NULL)//申请失败,报错返回{perror("malloc fail");return;}_MergeSort(a, 0, n - 1, tmp);//完成排序free(tmp);//申请的空间不使用之后要释放,防止内存泄漏tmp = NULL;
}