时空复杂度
时间复杂度:O(nlogn)
空间复杂度:O(n)
使用了分治思想
优势
1.稳定
归并的时空复杂度非常稳定的,不论是在哪种情况下,归并算法的时间复杂度都不变,
2.高效
归并算法计算效率相比其他算法也是非常快的
思路图解
分
把一个有n个元素的数组,分成n个有1个元素的数组
然后边比较边合并
治
合并子序列
需要将两个已经有序的子序列合并成一个有序序列
双指针依次比较,小的数先进入结果数组,进入后指针后移
直到所有数字都进入结果数组
函数组成
1.分离函数
使用递归,将数组分离到原子化
停止递归条件:x>=y,数组段已分离到只有一个元素
这里不开辟新数组来灌装,而是使用两个头尾index序号来表示分出的数组段
将数组段传入合并函数时,也是使用头尾序号的形式
void mergesort(int x,int y) //分离函数,参数x和y分别代表要分离数组段的开头和结尾
{
if (x>=y) return; //如果开头≥结尾,说明数组段已分离到只有一个元素,返回,停止分离
int mid=(x+y)/2; //将中间数求出来,用中间数把数列分成两段
mergesort(x,mid); //递归,继续分离分出的上半段
mergesort(mid+1,y); //递归,继续分离分出的下半段
merge(x,mid,y); //分离结束,进行合并函数
}
2.合并函数
由于没有开辟新的数组
需要合并的数组段在原数组序列中是紧挨在一起的,所以用三个参数index可表示两个数组段
第一段:low~mid,第二段:mid+1~high
合并是需要将两个无序数组段合并为一段有序数组
用两个指针 i、j,放在两段序列的开头,比较所指对象,较小的先进入结果数组,然后进入结果的指针后移
使用递归进行合并
结束条件:
两个数组的比较指针i、j 都已移动到数组结尾(i = mid和 j = high)
未达到结束条件就继续递归调用本函数或使用循环
void merge(int low,int mid,int high) //归并
//low 和 mid是要合并的第一个数列的开头和结尾,mid+1 和 high是第二个数列的开头和结尾
{
vector<int> ans(n); //用来合并的临时数组,合并完成后灌装进原数组
int i=low,j=mid+1,k=low; //两个比较指针,一个结果输入指针
while (i<=mid && j<=high) //如果两个数列的数都没放完,循环
{
if (a[i]<a[j]) //若后者大于前者
ans[k++]=a[i++]; //后者入答案数组,且后指针与档案指针后移一格
//k++:先赋值,再加一
else //若前者大于前者
ans[k++]=a[j++]; //前者入答案数组,且前指针与档案指针后移一格
} //k++:先赋值,再增加
while (i<=mid) //若一个数列已放完,前数组还没放玩,就把剩下的都塞进结果数组
ans[k++]=a[i++];
while (j<=high) //若一个数列已放完,后数组还没放玩,就把剩下的都塞进结果数组
ans[k++]=a[j++];
for (int i=low;i<=high;i++)
a[i]=ans[i]; //将排好的结果数组灌装入原数组的位置