【C++练习】42. 归并排序
·
归并排序
归并排序的思路
归并排序是一种分治算法,通过递归将数组拆分为更小的子数组,再逐步合并已排序的子数组。其核心思想是将两个有序数组合并为一个更大的有序数组。
递归拆分阶段:将数组不断对半分割,直到子数组长度为1(天然有序)。
合并阶段:将两个有序子数组合并为一个有序数组,通过双指针遍历比较元素大小,依次选择较小的元素放入结果数组。
归并排序的C++实现
#include <vector>
using namespace std;
void merge(vector<int>& arr, int left, int mid, int right) {
vector<int> temp(right - left + 1);
int i = left, j = mid + 1, k = 0;
// 比较左右子数组元素,按序放入临时数组
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 (int p = 0; p < k; p++) {
arr[left + p] = temp[p];
}
}
void mergeSort(vector<int>& arr, int left, int right) {
if (left >= right) return;
int mid = left + (right - left) / 2;
mergeSort(arr, left, mid); // 递归排序左半部分
mergeSort(arr, mid + 1, right); // 递归排序右半部分
merge(arr, left, mid, right); // 合并两部分
}
代码详解
merge函数:负责合并两个有序子数组。通过双指针i和j分别遍历左右子数组,比较当前元素大小,将较小的放入临时数组。当某一子数组遍历完成后,将另一子数组剩余元素直接追加到临时数组末尾。最后将临时数组数据拷贝回原数组的对应位置。
mergeSort函数:递归拆分数组直至子数组长度为1。计算中点mid后,分别对左右子数组递归调用mergeSort,最后调用merge合并已排序的子数组。
关键点:
- 时间复杂度: O ( n l o g n ) O(n log n) O(nlogn),递归深度为log n,每层合并操作需 O ( n ) O(n) O(n)。
- 空间复杂度: O ( n ) O(n) O(n),合并时需要临时数组存储数据。
- 稳定性:相等元素的相对顺序不变,是稳定排序。
常用实现方法
递归实现归并排序
递归方法是最经典的归并排序实现方式。通过将数组不断分成两半,直到子数组长度为1,然后合并排序后的子数组。
void merge(int arr[], int l, int m, int r) {
int n1 = m - l + 1;
int n2 = r - m;
int L[n1], R[n2];
for (int i = 0; i < n1; i++)
L[i] = arr[l + i];
for (int j = 0; j < n2; j++)
R[j] = arr[m + 1 + j];
int 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) return;
int m = l + (r - l) / 2;
mergeSort(arr, l, m);
mergeSort(arr, m + 1, r);
merge(arr, l, m, r);
}
迭代实现归并排序
迭代方法避免了递归调用的开销,使用循环和变量控制来模拟递归过程。
void merge(int arr[], int l, int m, int r) {
// 合并逻辑与递归实现相同
}
void mergeSort(int arr[], int n) {
int curr_size;
int left_start;
for (curr_size = 1; curr_size <= n - 1; curr_size = 2 * curr_size) {
for (left_start = 0; left_start < n - 1; left_start += 2 * curr_size) {
int mid = min(left_start + curr_size - 1, n - 1);
int right_end = min(left_start + 2 * curr_size - 1, n - 1);
merge(arr, left_start, mid, right_end);
}
}
}
使用STL实现归并排序
可以利用C++标准库中的std::merge和std::inplace_merge简化实现。
#include <algorithm>
#include <vector>
void mergeSort(std::vector<int>& arr, int l, int r) {
if (l >= r) return;
int m = l + (r - l) / 2;
mergeSort(arr, l, m);
mergeSort(arr, m + 1, r);
std::inplace_merge(arr.begin() + l, arr.begin() + m + 1, arr.begin() + r + 1);
}
并行归并排序
对于大型数据集,可以使用多线程加速归并排序过程。注意需要合理处理线程同步和数据分割。
#include <thread>
#include <vector>
void parallelMergeSort(int arr[], int l, int r, int depth = 0) {
if (l >= r) return;
int m = l + (r - l) / 2;
if (depth < std::thread::hardware_concurrency()) {
std::thread left(parallelMergeSort, arr, l, m, depth + 1);
parallelMergeSort(arr, m + 1, r, depth + 1);
left.join();
} else {
parallelMergeSort(arr, l, m, depth);
parallelMergeSort(arr, m + 1, r, depth);
}
merge(arr, l, m, r);
}
优化空间使用
传统归并排序需要额外空间,可以通过以下方法优化:
- 原地归并排序(较复杂且可能影响时间复杂度)
- 交替使用输入数组作为辅助空间
void mergeSortOptimized(int arr[], int n) {
int* temp = new int[n];
for (int size = 1; size < n; size *= 2) {
for (int left = 0; left < n; left += 2 * size) {
int mid = min(left + size - 1, n - 1);
int right = min(left + 2 * size - 1, n - 1);
if (mid < right) {
merge(arr, temp, left, mid, right);
}
}
}
delete[] temp;
}
更多推荐
所有评论(0)