代码演示
#include <stdio.h>
#include <stdlib.h>
//辅助函数: 打印数组
void print_arr(int arr[], int n) {
int i = 0;
for (i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
//合并
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++];
}
//把临时数组中合并后的元素复制回原来的数组
while (left <= right) {
arr[left] = tempArr[left];
left++;
}
}
//归并排序
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);
}
}
//归并排序入口
void merge_sort(int arr[], int n) {
//分配一个辅助数组
int *tempArr = (int *)malloc(n * sizeof(int));
if (tempArr) { //分配成功
msort(arr, tempArr, 0, n - 1);
free(tempArr);
} else {
printf("error: failed to allocate memory");
}
}
int main() {
int arr[] = {9, 5, 2, 7, 12, 4, 3, 1, 11};
int n = 9;
print_arr(arr, n);
merge_sort(arr, n);
print_arr(arr, n);
return 0;
}
算法简介
归并排序是一种经典的排序算法,它基于分治的思想,将一个待排序的序列逐步划分为较小的子序列,然后通过合并操作将这些子序列有序地合并成一个有序序列。
下面是归并排序的基本步骤:
- 分割:将待排序序列不断二分,直到每个子序列只包含一个元素或为空。
- 合并:将相邻的子序列两两合并,合并过程中保持元素的有序性。具体操作是比较两个子序列的首元素,将较小的元素放入新的序列,并将该子序列的指针向后移动,重复这个过程直到某个子序列为空,然后将另一个非空子序列的剩余部分直接拷贝到新序列中。
- 重复合并操作,直到所有子序列都合并成一个完整的有序序列。
归并排序的关键在于合并操作,它需要额外的空间来存储合并过程中产生的临时序列。因此,在实际应用中,归并排序的空间复杂度为O(n),其中n为待排序序列的长度。时间复杂度为O(nlogn),这是由于每次合并操作需要O(n)的时间,而分割操作需要进行logn次。
归并排序是一种稳定的排序算法,适用于各种数据规模和类型的排序任务。它的主要优点是在最坏情况下仍具有较好的性能,并且可以有效地处理大型数据集。然而,归并排序需要额外的空间来存储临时序列,这可能在内存受限的环境下造成问题。
总之,归并排序是一种高效、稳定的排序算法,通过分治和合并操作实现将待排序序列有序化。