归并排序基本思想
二分法、分治法、递归思想。
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
归并排序基本流程
说法1.按照二分思想,先将序列分成两个大小大致相同的2个子集合,分别对2个子集合进行排序(段内有序),最终将排好序的子集合合并成为所要求的排好序的集合(段间有序)。
说法2.从整体来看,假设初始序列有n个元素,实际是将它看成n个有序的子序列(长度是1),然后两两归并,直到得到长度是n的有序子序列。
时间复杂度分析:平均时间复杂度得出是,是渐近意义下的最优排序算法。原因:考虑两两归并的过程,每一层进行n次比较,归并树的高度是
,因此得解。
空间复杂度分析:
在合并有序数组时需要额外的辅助空间,递归也要调用栈的空间,整体复杂度。
稳定性分析:是稳定的排序(相同元素相对位置不变)。
如图是代码所示的2路-归并排序(同理可以有3路、4路)。
代码注意点
1.写递归程序要注意写结束条件(if(low>=high))。
2.合并时必须申请新的存储空间,不可以在原始数组上操作。
3.for循环后还可能有没有合并的元素,需要while循环直接合并剩下的元素。
//归并排序
#include<iostream>
#include<cstring>
#include<cstdlib>
using namespace std;
void merge(int a[],int low,int mid,int high)
//合并a[low...mid]和a[mid+1...high] (有序)
{
int *tmp = new int[high-low+1]; //动态分配临时空间
int i,j,k;//临时变量
for(i=low,j=mid+1,k=0;i<=mid && j<=high;k++)
//注意循环条件,当有一边的元素合并完成后即不满足循环条件
{
if(a[i]<a[j])
{
tmp[k]=a[i];
i++;
}
else{
tmp[k]=a[j];
j++;
}
}
while(i<=mid)//归并可能存在的剩余元素(左)
{
tmp[k]=a[i];
k++;i++;
}
while(j<=high)//归并可能存在的剩余元素(右)
{
tmp[k]=a[j];
k++;j++;
}
for(int i=0;i<k;i++)
{
a[low+i]=tmp[i];
//把临时数组的元素存回原始数组
}
delete []tmp;//释放临时空间
}
void mergeSort(int a[],int low,int high)
{
if(low>=high) return; //当只有一个元素时返回
if(low<high)
{
int mid = (low+high)/2;
mergeSort(a,low,mid); //二分法
mergeSort(a,mid+1,high); //递归调用
merge(a,low,mid,high);//合并有序序列
}
}
int main(void)
{
int n = 10;
int arr[10] = {0};
for(int i=0;i<n;i++)
{
arr[i]=rand()%100;
}
for(int i=0;i<n;i++)
{
cout<<arr[i]<<" ";
}
cout<<endl;
mergeSort(arr,0,n-1);
for(int i=0;i<n;i++)
{
cout<<arr[i]<<" ";
}
return 0;
}