归并排序
归并排序(MergeSort)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
简单来说归并排序类似于对两个有序序列的合并。
思路
也就是说,将待排序的序列分成 N 组,然后对这 N 个组两两合并成一个新的有序序列,接着继续两两合并,直至最终只有一个有序序列结束。这个过程就是先将待排序序列分组,直至每个组内只有一个元素,这个 时候任意一个组都是有序的,接着将这些两两合并,最后得到一个有序序列。
在这样分组完毕之后,每个组内元素都只剩一个,那么一个元素一定是有序的。这时候对相邻的两个元素进行归并排序。两两排序完毕后再与其相邻组继续归并,直至结束。
实现
递归版本
void MergeArray(int array[], int beg, int mid, int end, int* tmp)
{
int index = beg;
int cur1 = beg;
int cur2 = mid;
while (cur1 < mid && cur2 < end) {
if (array[cur1] < array[cur2]) {
tmp[index++] = array[cur1++];
} else {
tmp[index++] = array[cur2++];
}
}
while (cur1 < mid) {
tmp[index++] = array[cur1++];
}
while (cur2 < end) {
tmp[index++] = array[cur2++];
}
memcpy(array + beg, tmp + beg, (end - beg)*sizeof(int)); // 将临时区域内有序数据拷贝至原数组
return;
}
void _MergeSort(int array[], int beg, int end, int* tmp) // 分组
{
if (beg >= end - 1) {
return;
}
int mid = beg + (end - beg) / 2;
_MergeSort(array, beg, mid, tmp);
_MergeSort(array, mid , end, tmp);
MergeArray(array, beg, mid, end, tmp); // 归并函数
}
void MergeSort(int array[], int size)
{
if (size <= 1) {
return;
}
int* tmp = (int*)malloc(sizeof(int) * size); // 创建临时区域存放归并后的数组
_MergeSort(array, 0, size, tmp);
free(tmp);
tmp = NULL;
}
非递归版本
void MergeSortByLoop(int array[], int size)
{
if (size <= 1) {
return;
}
int size_bound = 1;
int* tmp = (int*)malloc(sizeof(int) * size);
for (; size_bound < size; size_bound *= 2) {
int i = 0;
for (; i < size; i += 2 * size_bound) {
int beg = i;
int mid = beg + size_bound;
int end = mid + size_bound;
// 如果此时的 mid 超过了 size
// 那么就意味着此时的区间只剩下了一个
// 即 [beg, mid) 那么这个时候
// mid 需要置为 size 防止越界
if (mid >= size) {
mid = size;
}
// 这里同理,如果 end 超过了 size
// 那么就是第二段的区域的元素个数低于第一段
// 也需要将 end 置为 size
if (end >= size) {
end = size;
}
MergeArray(array, beg, mid, end, tmp);
} // end for (; i < size; i += 2 * size_bound)
}
return;
}
归并排序的速度是非常快的,它的速度仅仅次于快速排序。是一个稳定的排序算法,时间复杂度为 O (N * log N)。在用于排序一个整体无序但各个元素之间相对有序的序列时效率很高。
欢迎大家共同讨论,如有错误及时联系作者指出,并改正。谢谢大家!