归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。
其基本思路是:
mergeSort(DataList & d)
if lenght of d <= 1 return;
mergeSort(d的左半子序列);
mergeSort(d的右半子序列);
归并d的左右半子序列;
end function
从上面伪代码中可以看出,归并是一个递归的过程。其基本思路类似于快速排序。这里需要说明的就是归并的过程。我们可以只讨论2路归并。所谓两路归并就是将两个有序表合成一个新的有序表。
有序表的合并思路很简单,对两个有序表遍历,比较对应位置元素大小,然后按照比较规则将排序码较小(较大,下面代码中使用的较小)的放到给定的辅助数组中;循环处理直到某个有序表遍历完成;之后将未遍历完的有序表添加到辅助数组中,最后将数据复制后原数组。
通常情况下两个有序表的连续的,下面代码中假定我们的数据列表使用数组。
代码如下:
void merge(Type *a, Type *b, int left, int mid, int right)
// a,b分别是原始数据数组和辅助数组
// a[left]...a[mid]表示第一个有序表
// a[mid+1]...a[right]表示第二个有序表
// 说明:a,b大小相同
{
int iL = left, iR = mid + 1; // 待合并有序表的位置索引
int iM = left; // 辅助数组的索引
while (iL <= mid && iR <= right) {
if (a[iL] < a[iR]) b[iM++] = a[iL++];
else b[iM++] = a[iR++];
}
// 将未处理的有序表直接复制到辅助数组中(下面两个循环仅有一个可能执行的)
while (iL <= mid) b[iM++] = a[iL++];
while (iR <= right) b[iM++] = a[iR++];
// 将排序号的数据复制到原始有序表中
for (iL = left; iL <= right; ++iL) {
a[iL] = b[iL];
}
}
具体的实现归并排序按照伪代码就可以简单实现,这里不赘述了。
可以改进的地方:
通常很到资料或者书籍上的介绍是先将数据复制到辅助数组然后对辅助数组中的数据进行归并,归并结果放在原始数据中。一种给进就是针对检查子序列是否结束的,其基本方法是:在把元素复制到辅助数组的过程中,第二个有序表的元素顺序逆转,这样两个待归并的表从两端开始处理,向中间归并。
另一种想法是将递归过程转化为非递归过程。