1 基本思想
归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列:即先使每个子序列有序,在使子序列段间有序。若将两个有序表合并称一个有序表,称为二路归并。
2 算法示意图
3 递归实现归并排序
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//tmp辅助空间 arr待排序数组
void merge(int* arr, int begin, int mid, int end, int* tmp) {
//递增
int begin1 = begin;
int end1 = mid;
int begin2 = mid + 1;
int end2 = end;
//辅助空间的起始位置
int idx = begin;
//合并有序序列
while (begin1 <= end1 && begin2 <= end2) {
if (arr[begin1] <= arr[begin2]) {
tmp[idx] = arr[begin1];
idx++;
begin1++;
}
else {
tmp[idx] = arr[begin2];
idx++;
begin2;
}
}
//判断是否有未合并的元素
if (begin1 <= end1)
memcpy(tmp+idx, arr+begin1, sizeof(int)*(end1 - begin1 + 1));
if (begin2 <= end2)
memcpy(tmp + idx, arr + begin2, sizeof(int) * (end2 - begin2 + 1));
//合并之后的序列拷到原始数组的对应区间
memcpy(arr + begin, tmp + begin, sizeof(int) * (end - begin + 1));
}
void _mergeSort(int* arr, int begin, int end, int* tmp) {
if (begin >= end)
return;
int mid = begin + (end - begin) / 2;
//首先合并子序列
_mergeSort(arr, begin, mid, tmp);
_mergeSort(arr, mid + 1, end, tmp);
//合并两个有序的子序列
merge(arr, begin, mid, end, tmp);
}
void mergeSort(int* arr, int n) {
//申请辅助空间
int* tmp = (int*)malloc(sizeof(int) * n);
_mergeSort(arr, 0, n - 1, tmp);
free(tmp);
}
4 代码验证
void testMergeSort() {
int arr[] = { 9 ,1,2,5,7,4,8,6,3,5 };
int n = sizeof(arr) / sizeof(arr[0]);
mergeSort(arr, n);
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
}
int main() {
testMergeSort();
return 0;
}
程序运行结果如下:
5 非递归实现归并排序
void mergeSortNOR(int* arr, int n) {
//子序列的步长
int step = 1;
int* tmp = (int*)malloc(sizeof(int) * n);
while (step < n) {
for (int idx = 0; idx < n; idx = idx + 2 * step) {
int begin = idx;
int mid = idx + step - 1;
//判断是否存在第2个序列
//不存在则直接跳过
if (mid >= n - 1)
continue;
int end = idx + 2 * step - 1;
//判断第2个序列是否越界
if (end >= n)
end = n - 1;
merge(arr, begin, mid, end, tmp);
}
//更新步长
step = step * 2;
}
}
6 归并排序特性
- 归并的缺点在于需要 O ( N ) O(N) O(N)的空间复杂度,归并排序的思考更多的是解决在磁盘中的外排序问题。
- 时间复杂度: O ( N ∗ l o g N ) O(N*logN) O(N∗logN)
- 空间复杂度: O ( N ) O(N) O(N)
- 稳定性:稳定