1.算法思想:分治法
算法效率仅次于 快排
时间复杂度:O(nlog2n) (每次数组分一半的长度,知道长度为1,一共需要log2n次,每次都要指针比较n次,都耗费O(n))
2.算法步骤:
(1)确定分界点mid=(l+r)/2,并把数组分为左右两部分(与快排不同,快排随便一个数组里的值,归并则是取中间位置的下标值)
(2)递归排序左右两个部分,形成有序数组
(3)将两个有序数组合为一个有序数组
3.算法流程:
利用双指针循环算法
左右两个数组分别排序,并开辟一个新数组;将排序好的数组利用双指针,从头逐一比较;如果某一个值小,则放入数组,并且指针向后移动,以此类推;遇见相同值则放谁均可,如果某一指针已经到头,则把另一个数组剩余部分直接放进数组
4.模板:
public static void mergeSort(int []arr, int l ,int r)
{
if(l>=r) return;
int mid = l+r>>1; //设置中间分界点mid=(l+r)/2
int res[]=new int[arr.length]; //开辟新数组
mergeSort(arr, l, mid); //递归左右两部分数组
mergeSort(arr, mid + 1, r);
int k=0,i=l,j=mid+1;
while(i<=mid && j<=r)
{
if(arr[i]<=arr[j]) res[k++]=arr[i++]; //移动两部分数组指针,比较值
else res[k++]=arr[j++];
}
//比较完后,有数组指针还没到头,就把该数组剩余部分直接加进数组里
while(i<=mid) res[k++]=arr[i++];
while(j<=r) res[k++]=arr[j++];
for(i=l,j=0;i<=r;i++,j++) arr[i]=res[j];
}
★递归理解:
归并排序递归-分治理解:从大方向考虑是将数组一分为二,分别递归左右两边,最后合并。事实上从递归角度分析,左右两边是会一直二分下去的,也就是左、右两边的数组还会再不断产生新的左右数组,然后再二分,再产生左右数组......这样不断二分下去,直到递归最深处,也就是只剩下一个元素不能再分的时候(l>=r),这时候递归停止,开始往前回溯。整个递归过程等同于一棵二叉树,从开始的一个数组的根节点,直到最后不可分的叶节点;等递归结束回溯时候可将叶节点的一个元素看成只有一个元素的有序数组,这个时候开始不断比较、合并,逐渐合并成最开始的状态,这样的结果一定是两个有序数组,然后两个数组再进行归并,就可以排序成新的有序数组了。