1. 归并排序
核心思想:
- 分解,将待排序序列递归地分成两个子序列,直到每个子序列仅含有一个元素(此时天然有序)。
- 将两个有序子序列合并成为一个更大的有序序列,最终得到完整的有序序列。
实现代码(C语言实现):
- 迭代实现归并排序的代码
void Merge(int arr[], int low, int mid, int high) {int i = low, j = mid + 1, k = 0;int *temp = (int *)malloc((high - low + 1) * sizeof(int)); // 辅助数组while (i <= mid && j <= high) {if (arr[i] <= arr[j]) temp[k++] = arr[i++]; // 保证稳定性else temp[k++] = arr[j++];}// 处理剩余元素while (i <= mid) temp[k++] = arr[i++];while (j <= high) temp[k++] = arr[j++];// 将temp数组拷贝回原数组for (i = low, k = 0; i <= high; i++, k++) {arr[i] = temp[k];}free(temp);
}void MSort(int arr[], int low, int high) {if (low < high) {int mid = (low + high) / 2;MSort(arr, low, mid); // 递归左半部分MSort(arr, mid + 1, high); // 递归右半部分Merge(arr, low, mid, high); // 合并}
}void MergeSort(int arr[], int n) {MSort(arr, 0, n - 1);
}
- 非递归实现的归并排序
// 合并两个有序子数组
void Merge(int arr[], int left, int mid, int right) {int n1 = mid - left + 1;int n2 = right - mid;int *L = (int *)malloc(n1 * sizeof(int));int *R = (int *)malloc(n2 * sizeof(int));// 拷贝数据到临时数组for (int i = 0; i < n1; i++) L[i] = arr[left + i];for (int j = 0; j < n2; j++) R[j] = arr[mid + 1 + j];// 合并int i = 0, j = 0, k = left;while (i < n1 && j < n2) {if (L[i] <= R[j]) arr[k++] = L[i++];else arr[k++] = R[j++];}// 处理剩余元素while (i < n1) arr[k++] = L[i++];while (j < n2) arr[k++] = R[j++];free(L);free(R);
}// 非递归归并排序
void MergeSort(int arr[], int n) {for (int step = 1; step < n; step *= 2) { // 子数组长度从1开始翻倍for (int left = 0; left < n - 1; left += 2 * step) {int mid = left + step - 1;int right = (left + 2 * step - 1) < (n - 1) ? (left + 2 * step - 1) : (n - 1);Merge(arr, left, mid, right); // 合并相邻子数组}}
}
归并排序的特点:
-
归并排序具有稳定性,可以用于需要保持关键字原始顺序的场景。
-
可以用于大数据排序(外部排序,具体见\(\rightarrow\)8.7.外部排序),链表排序(无需随机访问,合并操作非常适合链表结构)。
-
不适用于有内存限制的问题(需要\(O(n)\))的辅助空间,也不适用于实时系统(递归调用和空间开销较大)。
-
虽然归并排序和快速排序的时间复杂度相同,但是归并排序的常数因子较大,实际运行可能慢于快速排序。
2. 基数排序
待补······