目录
[一 简介](#一 简介)
[二 代码实现](#二 代码实现)
[三 时空复杂度](#三 时空复杂度)
一 简介
归并排序(Merge Sort)是一种基于分治策略的高效排序算法,其基本思想是将一个大问题分解为若干个规模较小且相互独立的相同子问题进行解决,然后再合并这些子问题的解以得到原问题的解。在C语言中实现归并排序通常包括两个主要步骤:分解 和合并。
二 代码实现
下面是一个简单的C语言实现归并排序的例子:
cpp
#include <stdio.h>
#include <stdlib.h>
// 归并操作函数,用于合并两个已排序数组
void merge(int arr[], int l, int m, int r) {
int i, j, k;
int n1 = m - l + 1;
int n2 = r - m;
// 创建临时数组
int L[n1], R[n2];
// 将arr[l...m]复制到L[]中
for (i = 0; i < n1; i++)
L[i] = arr[l + i];
// 将arr[m+1...r]复制到R[]中
for (j = 0; j < n2; j++)
R[j] = arr[m + 1 + j];
// 合并两个有序数组
i = 0;
j = 0;
k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
// 将剩余部分复制回原数组
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
}
// 分治法实现归并排序
void mergeSort(int arr[], int l, int r) {
if (l < r) {
// 找到中间点
int m = l + (r - l) / 2;
// 递归地对左半部分进行归并排序
mergeSort(arr, l, m);
// 递归地对右半部分进行归并排序
mergeSort(arr, m + 1, r);
// 合并两个已排序的部分
merge(arr, l, m, r);
}
}
// 测试归并排序函数
int main() {
int arr[] = {12, 11, 13, 5, 6, 7};
int arr_size = sizeof(arr) / sizeof(arr[0]);
printf("原始数组: \n");
for (int i = 0; i < arr_size; i++)
printf("%d ", arr[i]);
mergeSort(arr, 0, arr_size - 1);
printf("\n排序后的数组: \n");
for (int i = 0; i < arr_size; i++)
printf("%d ", arr[i]);
return 0;
}
在这段代码中:
merge
函数负责将两个已经排好序的子数组合并成一个有序数组。mergeSort
函数实现了归并排序的核心逻辑,通过递归不断将待排序数组一分为二,直到子数组只剩下一个元素或者为空,然后调用merge
函数逐步合并子数组,最终完成整个数组的排序。
三 时空复杂度
归并排序(Merge Sort)的时间复杂度和空间复杂度如下:
A.时间复杂度:
- 最好情况:无论输入数组是否有序,归并排序的平均和最坏时间复杂度都是相同的。
- 平均情况 :时间复杂度为 ,其中 n 是待排序数组中的元素数量。这是因为归并排序采用分治策略,每次都将问题规模减半,然后合并两个已排序部分的时间与 n 成线性关系,由于分解次数是 级别的,所以总的时间复杂度为 。
B.空间复杂度:
- 额外空间:归并排序需要一个临时数组来合并两个已排序的子数组,这个临时数组的大小与原始数组相同。因此,归并排序的空间复杂度是 O(n)。在递归过程中,每一层递归都会消耗额外空间,但由于这些空间只在合并阶段使用,并且在合并完成后会被释放,故在任意时刻只会有一个临时数组占用内存,其大小最多等于原数组长度。
C.总结:
总结来说,归并排序虽然具有较高的额外空间需求,但它是一种稳定的排序算法,且在所有情况下都能保证 的时间复杂度,适用于大规模数据集的排序任务。