归并排序的核心思想是分治法,即将待排序数据分成多个小块,对每个小块进行排序,然后在两两合并小块,最终完成对整体的排序
时间复杂度是nlogn
输入:25,12,17,21,15,48
结果:
递归实现:递归类似于对此方法的场景再现,即先对整体进行划分,然后对划分后的部分进行排序(对递归函数的理解可以认为是从上层向下层进入),排序好之后再进行合并(可以认为是从下层上层开始返回)代码如下:
//归并排序
void MergeSort(int arr[],int length)
{
if(length<=1||arr==NULL)return;
MergeSortRecursion(arr,0,length-1);
}
//把检查边缘问题放在递归循环的外侧
void MergeSortRecursion(int arr[],int low,int high)//high表示最高坐标
{
if(low==high)return;
int mid=(low+high)/2;
MergeSortRecursion(arr,0,mid);
MergeSortRecursion(arr,mid+1,high);
//归并
int *tmp=new int[high-low+1];
//如果内存分配不足,两侧成分已排序好,直接返回
if(tmp==NULL) return;
int i=low;int j=mid+1;int curTmp=0;
while(i<=mid&&j<=high)
{
if(arr[i]>arr[j])//升序
{
tmp[curTmp++]=arr[j++];
}else
{
tmp[curTmp++]=arr[i++];
}
}
if(i<=mid)
{
for(;i<=mid;i++)
tmp[curTmp++]=arr[i];
}
if(j<=high)
{
for(;j<=high;j++)
tmp[curTmp++]=arr[j];
}
//返还给arr
curTmp=0;
for(int i=low;i<=high;i++)
arr[i]=tmp[curTmp++];
delete[] tmp;
}
非递归的实现是对递归形式的模拟,但是不能够实现从上到下在由下到上的返回,因此我们之间利用从下向上返回的模拟,利用step一步一步上向上层爬,一直爬到最上层,具体代码如下:
//非递归
void MergeSortNonRecursion(int arr[],int length)//length表示数组长度
{
int *tmp=new int[length];
int step=1;
while(step<length)//由于步长小于length所以左侧的必然存在
{
int i=0;//控制坐标变化
int left,right,leftToPos,rightToPos;
while(i<length)
{
left=i;leftToPos=left+step-1;
right=leftToPos+1;//保证剩下的部分不足low+step时用剩余部分
rightToPos=right+step-1>length-1?length-1:right+step-1;
int p=left;int q=right;int k=left;
while(p<=leftToPos&&q<=rightToPos)
{
if(arr[p]>arr[q])//升序
{
tmp[k++]=arr[q++];
}else
{
tmp[k++]=arr[p++];
}
}
if(p<=leftToPos)
{
while(p<=leftToPos)
tmp[k++]=arr[p++];
}
if(q<=rightToPos)
{
while(q<=rightToPos)
tmp[k++]=arr[q++];
}
//返还给arr
for(int j=left;j<=rightToPos;j++)
{
arr[j]=tmp[j];
}
i+=2*step;
}
step*=2;
}
delete[] tmp;
}
数组做参数退化成指针类型