基本思想
归并排序一般指2-路归并排序。基本思想如下:
第一个问题:
1、假设待排序列由两段有序的左右子序列拼接而成
2、那么只需要一个额外空间当辅助空间,从左段和右段的第1开始比较,小的放到额外空间的低位。一直到两段排完
第二个问题:
1、如何让这两段序列有序?
2、试想如果序列长度为2,那么可看成是左右两段有序子序列。
3、那么只需要将长度为n的看成n个有序的子序列。
4、每个子序列用第一个问题的思想两两拼接成一段长度为2的序列
5、拼接好的序列再一次拼接,直到最后最后排完。
实现
第一个问题的实现:
把两段子序列拼接到vector T,再复制回原来的数组nums
最后两个while是当两段其中一段已全部归并了,而另外一段还没有,
剩下的部分一定是最大的,可以直接将剩余部分复制到 T 对应的位置。
void Merge(vector<int>&nums,unsigned low,unsigned mid,unsigned high){
unsigned i=low,j=mid+1,k=low;
while(i<=mid&&j<=high){
if(nums[i]<=nums[j])
T[k++]=nums[i++];
else
T[k++]=nums[j++];
}
while(i<=mid) T[k++]=nums[i++];
while(j<=high) T[k++]=nums[j++];
for(unsigned tn=low; tn<=high;tn++) nums[tn]=T[tn];
}
第二个问题的实现:
将长序列不停划分成两段,直到长度为 1;
函数往回递归,程序回到Merge(nums,low,mid,high)语句将两段
合为一段;
递归到最后则全部序列排序完成。
void Msort(vector<int>& nums,unsigned low ,unsigned high){
if(low==high) return;
else{
unsigned mid = (low+high)/2;
Msort(nums,low,mid);
Msort(nums,mid+1,high);
Merge(nums,low,mid,high);
}
}
测试:
T为全局的vector
vector<int> vec{7,5,6,4,4,3,2,6,78,45,
32,0,23,54,2,34,99,55};
T.resize(vec.size());
Msort(vec,0,vec.size()-1);
for(int data : vec)
cout<<data<<" ";
cout<<endl;
结果:
分析:
每次划分成两段,划分log2n次;
两段合并成一段,每次操作不超过n次;
时间复杂度为O(nlog2n);
借助中间数组T长度为n;
空间复杂度为O(n)。