归并排序(Merge Sort)是一种基于比较的排序算法。它将待排序的数组分成两个子数组,分别对这两个子数组进行排序,然后将已排序的子数组合并成一个有序数组。归并排序的核心思想是“分而治之”,即将一个大问题分解成若干个小问题逐一解决。
以下是归并排序的基本实现代码:
#include <stdio.h>
#include <stdlib.h>
// 合并两个子数组的函数
void merge(int arr[], int left, int mid, int right) {
int i, j, k;
int n1 = mid - left + 1;
int n2 = right - mid;
// 创建临时数组
int *L = (int *)malloc(n1 * sizeof(int));
int *R = (int *)malloc(n2 * sizeof(int));
// 拷贝数据到临时数组 L[] 和 R[]
for (i = 0; i < n1; i++)
L[i] = arr[left + i];
for (j = 0; j < n2; j++)
R[j] = arr[mid + 1 + j];
// 重新合并数组 L[] 和 R[] 到 arr[]
i = 0; // 初始化第一个子数组的索引
j = 0; // 初始化第二个子数组的索引
k = left; // 初始化合并后数组的索引
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
// 拷贝 L[] 中的剩余元素(如果有)
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
// 拷贝 R[] 中的剩余元素(如果有)
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
// 释放临时数组
free(L);
free(R);
}
// 归并排序函数
void mergeSort(int arr[], int left, int right) {
if (left < right) {
int mid = left + (right - left) / 2;
// 递归排序两个子数组
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
// 合并已排序的子数组
merge(arr, left, mid, right);
}
}
// 打印数组函数
void printArray(int arr[], int size) {
for (int i = 0; i < size; i++)
printf("%d ", arr[i]);
printf("\n");
}
// 主函数
int main() {
int arr[] = {12, 11, 13, 5, 6, 7};
int arr_size = sizeof(arr) / sizeof(arr[0]);
printf("未排序的数组: \n");
printArray(arr, arr_size);
mergeSort(arr, 0, arr_size - 1);
printf("排序后的数组: \n");
printArray(arr, arr_size);
return 0;
}
merge
:
L
和R
,分别存储左半部分和右半部分的元素。L
和R
中的元素,按顺序将较小的元素放入原数组中。mergeSort
:
merge
函数合并已排序的子数组。printArray
:
main
:
mergeSort
函数对数组进行排序。归并排序的基本实现已经相对高效,但仍有一些优化方法可以进一步提升性能:
优化内存分配:
优化代码示例:
void merge(int arr[], int left, int mid, int right, int temp[]) {
int i = left, j = mid + 1, k = left;
while (i <= mid && j <= right) {
if (arr[i] <= arr[j]) {
temp[k++] = arr[i++];
} else {
temp[k++] = arr[j++];
}
}
while (i <= mid) {
temp[k++] = arr[i++];
}
while (j <= right) {
temp[k++] = arr[j++];
}
for (i = left; i <= right; i++) {
arr[i] = temp[i];
}
}
void mergeSort(int arr[], int left, int right, int temp[]) {
if (left < right) {
int mid = left + (right - left) / 2;
mergeSort(arr, left, mid, temp);
mergeSort(arr, mid + 1, right, temp);
merge(arr, left, mid, right, temp);
}
}
int main() {
int arr[] = {12, 11, 13, 5, 6, 7};
int arr_size = sizeof(arr) / sizeof(arr[0]);
int *temp = (int *)malloc(arr_size * sizeof(int));
printf("未排序的数组: \n");
printArray(arr, arr_size);
mergeSort(arr, 0, arr_size - 1, temp);
printf("排序后的数组: \n");
printArray(arr, arr_size);
free(temp);
return 0;
}
小数组插入排序:
优化代码示例:
void insertionSort(int arr[], int left, int right) {
for (int i = left + 1; i <= right; i++) {
int key = arr[i];
int j = i - 1;
while (j >= left && arr[j] > key) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = key;
}
}
void mergeSort(int arr[], int left, int right, int temp[]) {
if (right - left <= 10) {
insertionSort(arr, left, right);
} else {
int mid = left + (right - left) / 2;
mergeSort(arr, left, mid, temp);
mergeSort(arr, mid + 1, right, temp);
merge(arr, left, mid, right, temp);
}
}
int main() {
int arr[] = {12, 11, 13, 5, 6, 7};
int arr_size = sizeof(arr) / sizeof(arr[0]);
int *temp = (int *)malloc(arr_size * sizeof(int));
printf("未排序的数组: \n");
printArray(arr, arr_size);
mergeSort(arr, 0, arr_size - 1, temp);
printf("排序后的数组: \n");
printArray(arr, arr_size);
free(temp);
return 0;
}
归并排序的时间复杂度为
,这是因为每次将数组对半分裂需要
次,而每次合并两个子数组的操作需要
时间。因此,归并排序在处理大型数据集时表现良好。
归并排序的空间复杂度为
,因为它需要额外的空间来存储临时数组。这也是归并排序的一大缺点,相较于一些原地排序算法(如快速排序)。
归并排序是一个稳定的排序算法,因为相同元素的相对位置不会改变。
归并排序由于其高效性和稳定性,在以下几种情况下非常有用:
2
. 外部排序:
归并排序是C语言中一种高效且稳定的排序算法,其基于分治法的思想使其在处理大型数据集时表现出色。尽管归并排序需要额外的空间,但通过合理的优化方法,可以在实际应用中达到良好的性能。通过本文的介绍,希望读者能够深入理解归并排序算法,并在实际编程中灵活应用。