目录
基本思想
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列区间有序。若将两个有序表合并成一个有序表,称为二路归并。
图解:
上面的解释比较官方。这里用自己的大白话来解释一下。
其归并排序的实现过程就是:
首先,先将一组数据分成两组,这里可以以中间值为界来划分。
然后,利用分治递归法,紧接着将这分开的两组以同样的以中间值为界的方法来划分为两组,一直到最后只剩一个数或为空的时候停下来。
停下来的这时,先将数据排序一下,也就是将这两组数据归并一下,然后将归并好的数据拷贝回原数据中去,最后回溯就ok了。
具体代码实现:
int main(){
TestMergeSort();
return 0;
}
void TestMergeSort() {
int a[] = {9, 10, 6, 5, 8, 1, 3, 4, 2};
int len = sizeof(a) / sizeof(a[0]);
MergeSort(a, len);
PrintfArray(a, len);
}
void MergeSort(int* a, int n) {
int* tmp = (int*)malloc(sizeof(int) * n);//实现归并排序得额外开辟一个与原数据同样大小的空间
if (tmp == NULL) {
printf("malloc is fail");
exit(-1);
}
_MergeSort(a, 0, n - 1, tmp);
}
void _MergeSort(int* a, int begin, int end, int* tmp) {//归并排序的主要实现代码
if (begin >= end) {//当递归到子区间只有一个或为空时回溯
return;
}
int mid = (begin + end) / 2;
//[begin, mid] [mid + 1,end]
//分治递归,让子区间变得有序
_MergeSort(a, begin, mid, tmp);
_MergeSort(a, mid + 1, end, tmp);
//归并
//也就是利用分治的思想,将一组数据看成两组,一组为[begin, mid]
//另一组为[mid + 1,end]
//然后分别从两组数据的开头开始比较,把较小的放入到临时创建的新数组当中去
//这样,当遍历完时,其临时创建的数组中的数据也就成为有序的了
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++];
}
//将归并且排序好了的数据拷贝回原数组中去
//记得加begin,因为有可能你拷贝的是已经归并到右边的那一组数据,也就是[mid + 1,end]
memcpy(a + begin,tmp + begin,(end - begin + 1) * sizeof(int));
}
代码解释:
if (begin >= end) {//当递归到子区间只有一个或为空时回溯
return;
}int mid = (begin + end) / 2;
//[begin, mid] [mid + 1,end]
//分治递归,让子区间变得有序
_MergeSort(a, begin, mid, tmp);
_MergeSort(a, mid + 1, end, tmp);以上这一段代码主要是将数据进行分治递归,从而将数据实现到上面的画绿色横线的那一步。感兴趣的可以跟着代码画画递归实现图,会容易理解很多。
实现完之后,其总体上就是这样的:
紧接着来进行归并(先进行左区间的):
到这里左半区间就变得有序了,同样的,右半区间也可以一样的实现。到这,也就完成了归并排序的讲解了。