归并排序是建立在归并操作上的排序算法,是采用分治法(Divide and Conquer)的一个非常典型的应用,它常用来做外排序。
若将两个有序表合并成一个有序表,称为二路归并。
外排序
外排序(External sorting)是指能够处理极大量数据的排序算法。通常来说,外排序处理的数据不能一次装入内存,只能放在读写较慢的外存储器(通常是硬盘)上。外排序通常采用的是一种“排序-归并”的策略。在排序阶段,先读入能放在内存中的数据量,将其排序输出到一个临时文件,依此进行,将待排序数据组织为多个有序的临时文件。之后在归并阶段将这些临时文件组合为一个大的有序文件,也即排序结果。常见的有外归并排序。
(参考:百度百科)
分治模式
分解:将n个元素分成各含n/2个元素的子序列;
解决:用归并排序法对两个子序列递归地排序;
合并:合并两个已排序的子序列以得到排序结果。
当子序列长度为1时,递归结束,单个元素被视为是已排好序的。
基于以上思路,我们写出归并排序的代码:
void mergeSort(int arr[], int l, int r)
{
if (NULL == arr || l >= r)
return ;
int m = l + (r-l)/2;
mergeSort(arr, l, m);
mergeSort(arr, m+1, r);
merge(arr, l, m, r);
}
接下来的重点就是merge()函数了。
二路归并
merge()函数将两个有序的数组合并成一个有序的数组。
为理解这个过程,我们以摸扑克牌为例:
桌面上有两堆已排好序的牌(比如最上面的牌最小),牌面朝上。我们的任务是将两堆牌合并成一堆有序的牌。
下面开始取牌:
从两堆牌顶上的两张牌中选取较小的一张,将其取出,面朝下放到输出堆中。如果反复取牌直到其中一堆牌为空,接下来只要把剩下那堆牌(如果有的话)的所有牌都取出并放到输出堆中即可。
如果有n张牌那么我至多只需要比较n次,所以合并的时间为O(n)。
我们将上面的想法用代码来实现:
void merge(int arr[], int l, int m, int r)
{
int index_l = l, index_r = m+