C语言递归实现归并排序详解
归并排序是一种基于分治策略的高效排序算法。本文将深入解析C语言中利用递归来实现归并排序的具体步骤、原理及完整代码。
归并排序的核心逻辑
归并排序(Merge Sort)采用“分而治之”的思想,主要包含两个阶段:
- 分割(Divide):将待排序数组从中间划分为左右两个子数组,递归地对左半区和右半区继续进行划分,直到子数组只包含一个元素时停止划分。此时,单个元素的数组天然有序。
- 合并(Conquer/Merge):从最底层开始,将两个已排序的子数组合并为一个新的有序数组。比较两个子数组的排头元素,将较小的放入临时数组,并移动对应指针。当其中一个子数组的元素全部处理完后,将另一个子数组剩余的部分直接追加到临时数组末尾。最后将临时数组中的结果复制回原数组。
C语言代码实现与解析
以下代码展示了如何在C语言中完整实现上述逻辑,包含内存分配、递归拆分、合并排序及资源释放的关键步骤。
#include<bits/stdc++.h>
using namespace std;
// 打印数组辅助函数
void print_arr(int arr[], int n){
for(int i=0; i<n; i++){
printf("%d ", arr[i]);
}
printf("\n");
}
/**
* 合并两个有序子数组
* @param arr 原数组
* @param tempArr 临时数组,用于存储合并后的结果
* @param left 左半区的起始索引
* @param mid 左半区的结束索引(右半区的起始位置为 mid+1)
* @param right 右半区的结束索引
*/
void merge(int arr[], int tempArr[], int left, int mid, int right){
int l_pos = left; // 左半区当前未排序元素的起始位置
int r_pos = mid + 1; // 右半区当前未排序元素的起始位置
int pos = left; // 临时数组当前写入位置的起始位置
// 当左右半区都还有元素时,进行比较并填入临时数组
while(l_pos <= mid && r_pos <= right) {
if(arr[l_pos] < arr[r_pos]) { // 左半区元素较小
tempArr[pos++] = arr[l_pos++];
} else { // 右半区元素较小或相等
tempArr[pos++] = arr[r_pos++];
}
}
// 如果左半区仍有剩余元素,将其追加到临时数组
while(l_pos <= mid) tempArr[pos++] = arr[l_pos++];
// 如果右半区仍有剩余元素,将其追加到临时数组
while(r_pos <= right) tempArr[pos++] = arr[r_pos++];
// 将临时数组中排好序的元素拷贝回原数组
pos = left;
while(pos <= right) {
arr[pos] = tempArr[pos];
pos++;
}
}
/**
* 递归执行归并排序
* @param arr 原数组
* @param tempArr 临时数组
* @param left 当前待排序区间的左边界
* @param right 当前待排序区间的右边界
*/
void msort(int arr[], int tempArr[], int left, int right){
// 基准条件:如果区间只有一个元素或为空,则无需进一步划分
if(left < right) {
int mid = (left + right) / 2;
// 递归对左半区进行排序
msort(arr, tempArr, left, mid);
// 递归对右半区进行排序
msort(arr, tempArr, mid + 1, right);
// 将两个已排序的半区合并
merge(arr, tempArr, left, mid, right);
}
}
/**
* 归并排序入口函数
* @param arr 待排序数组
* @param n 数组大小
*/
void merge_sort(int arr[], int n){
// 动态分配临时数组,避免在栈上重复分配
int* tempArr = (int*)malloc(n * sizeof(int));
if(tempArr != NULL) {
// 调用递归排序函数,处理范围从 0 到 n-1
msort(arr, tempArr, 0, n - 1);
// 释放临时数组内存
free(tempArr);
} else {
printf("Memory allocation failed!");
}
}
int main() {
int arr[] = {9, 5, 2, 7, 12, 4, 3, 1, 11};
int n = 9;
printf("原始数组: ");
print_arr(arr, n);
// 执行归并排序
merge_sort(arr, n);
printf("排序后数组: ");
print_arr(arr, n);
return 0;
}关键点说明
- 时间复杂度:归并排序在任何情况下(最好、最坏、平均)的时间复杂度均为
O(n log n),因为每次都将问题规模减半,且合并过程需要遍历所有元素。 - 空间复杂度:由于需要额外的临时数组来存储合并结果,空间复杂度为
O(n)。代码中通过malloc在入口处一次性分配内存,比在每次递归中分配更高效。 - 稳定性:归并排序是稳定的排序算法。在
merge函数中,当arr[l_pos] == arr[r_pos]时,优先选择左边的元素,从而保持了相等元素的相对顺序。
以上就是C语言递归实现归并排序的详细教程,更多关于C语言算法的文章,敬请关注本站!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









