归并排序
1. merge
函数
功能:合并两个已排序的子数组。
参数:
vector<int>& a
:待排序的数组。int l
:左边界索引。int m
:中间索引,将数组分为左右两个部分。int r
:右边界索引。
步骤:
-
计算子数组大小:
int n1 = m - l + 1; // 左子数组大小 int n2 = r - m; // 右子数组大小 int temp[n1 + n2]; // 创建临时数组存储合并结果
-
复制左子数组到临时数组:
for(int i = 0; i < n1; i++) { temp[i] = a[l + i]; // 将左子数组元素复制到temp }
-
复制右子数组到临时数组:
for(int j = 0; j < n2; j++) { temp[j + n1] = a[j + m + 1]; // 将右子数组元素复制到temp }
-
合并两个已排序的子数组:
- 使用三个索引:
i
(左子数组),j
(右子数组),k
(原数组)。 - 比较并填充到原数组
a
:
while(i < n1 && j < n1 + n2) { if(temp[i] < temp[j]) { a[k++] = temp[i++]; // 将较小的元素放回原数组 } else { a[k++] = temp[j++]; } }
- 使用三个索引:
-
处理剩余元素:
- 如果左子数组还有剩余元素:
while(i < n1) { a[k++] = temp[i++]; // 直接复制剩余元素 }
- 如果右子数组还有剩余元素:
while(j < n1 + n2) { a[k++] = temp[j++]; }
2. mergeSort
函数
功能:递归地分割数组并调用merge
进行合并。
参数:
vector<int>& a
:待排序的数组。int l
:当前处理的左边界索引。int r
:当前处理的右边界索引。
步骤:
-
递归终止条件:
if(l >= r) { return; // 当左边界大于或等于右边界时,停止递归 }
-
找到中间索引:
int m = (l + r) / 2; // 计算中间点
-
递归调用:
- 先对左半部分进行排序:
mergeSort(a, l, m);
- 再对右半部分进行排序:
mergeSort(a, m + 1, r);
-
合并已排序的子数组:
merge(a, l, m, r); // 将两个已排序的子数组合并
总结
归并排序的核心思想是“分治”,即将大问题分解为小问题,递归地解决每个小问题,再将它们合并成一个解决方案。该算法具有O(n log n)的时间复杂度,非常适合处理大型数组的排序。
class Solution {
void merge(vector<int>& a, int l, int m, int r){
int n1 = m-l+1;
int n2 = r-m;
int temp[n1+n2];
for(int i=0; i<n1; i++){
temp[i] = a[l+i];
}
for(int j=n1; j<n1+n2; j++){
temp[j] = a[j+m+1-n1];
}
// for(int j = 0; j<n2; j++){
// temp[j+n1] = a[j+m+1];
// }
int i = 0 , j = n1, k = l;
while(i<n1 && j<n1+n2){
if(temp[i]<temp[j]){
a[k++] = temp[i++];
}else{
a[k++] = temp[j++];
}
}
while(i<n1){
a[k++] = temp[i++];
}
while(j<n1+n2){
a[k++] = temp[j++];
}
return ;
}
void mergeSort(vector<int>& a, int l ,int r){
if(l>=r){
return;
}
int m = (l+r)/2;
mergeSort(a, l, m);
mergeSort(a, m+1, r);
merge(a,l,m,r);
return;
}
public:
vector<int> sortArray(vector<int>& nums) {
mergeSort(nums,0,nums.size()-1);
return nums;
}
};