实现
class Solution {
public:
vector<int> sortArray(vector<int>& nums) {
int n = nums.size();
vector<int> tmp(n);
mergeSort(nums,0,n-1,tmp);
return nums;
}
void mergeSort(vector<int> &nums,int l,int r,vector<int> &tmp){
if(l >= r)
return;
int mid = l + (r - l) / 2;
mergeSort(nums,l,mid,tmp);
mergeSort(nums,mid+1,r,tmp);
//若两个子序列已有序,无需合并
if(nums[mid] <= nums[mid + 1])
return;
mergeTwoArrs(nums,l,mid,r,tmp);
}
void mergeTwoArrs(vector<int> &nums,int l,int mid,int r,vector<int> &tmp){
int n = nums.size();
tmp = vector<int>(nums.begin(),nums.end());
int i = l, j = mid + 1;
for(int k = l; k <= r; k++){
if(i > mid)
nums[k] = tmp[j++];
else if(j > r)
nums[k] = tmp[i++];
//注意别写成<,不然会失去稳定性(要保证次序较前的相等元素先被赋值)
else if(tmp[i] <= tmp[j])
nums[k] = tmp[i++];
else
nums[k] = tmp[j++];
}
}
};
分析
时间复杂度:和堆排序一样,最好和最坏情况都是 O ( l o g N ) O(logN) O(logN)
空间复杂度:需要用到一个额外数组,故空间复杂度为 O ( N ) O(N) O(N)
稳定性: 如果能保证前一子序列的相同元素先于后一子序列的相同元素被赋值,则该算法就是稳定的
初始次序:
移动次数: 额外数组不管原数组不有序都会赋值,故移动次数与初始次序无关
比较次数: 额外数组不管原数组不有序都会赋值,而一次赋值必定先有一次比较,故比较次数与初始次序无关
时间复杂度: 最好和最坏情况都是 O ( l o g N ) O(logN) O(logN), 故时间复杂度与初始次序无关
排序趟数: 递归深度取决于数组的长度,固定二分,不受初始序列影响,故与初始序列无关(与此相对立的是快排,切分点受初始序列影响)
应用
对于内存敏感,无法一次性放入数据,又需要高速处理数据的机器,可将数组分组进行排序并合并处理。