归并排序Merge Sort(其一)自顶向下的递归实现

归并排序Merge Sort(其一)自顶向下的递归实现

归并排序 : 使用递归实现自顶向下的归并排序

  • 分治(divide-and-conquer)策略:分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之。
  • 时间复杂度 : O(NlogN)
  • 空间复杂度 : O(N)
  • 归并排序的关键:对于两个已经排好序的子数组,怎么进行归并排序使其成为一个有序的数组。
  • (设置三个索引,需要定义清楚k;i,j(维护这个定义))
  • left , middle, right
    基本思想:
    先把待排序的数组分成两半,然后把左边的子数组进行排序,再对右边的子数组进行排序,之后再将这两部分归并起来。当我们对左边的子数组和右边的子数组进行排序的时候,我们再分别对左边的子数组和右边的子数组分成两半,然后对每一个部分先排序再归并,对于这每一个部分,我们还是对它们分半之后归并。当分到一定细度时,每一部分只有一个元素了,我们不用排序,它本身就是有序的,只需要对其进行简单的一次归并就好了,归并到上一个层级后再进行归并,归并到一个更高的层级,一层层的向上归并,归并到最后一层时,整个数组就是有序的了。
    在这里插入图片描述
    归并的具体步骤:
    需要额外与arr相等的辅助空间copyArr,将待排序的数组元素arr赋值给copyArr,接下来进行归并操作。
    设置三个索引:i,j,k;i从copyArr的left开始,j从copyArr的middle+1开始,k为归并索引,指向下一个需要考虑的位置,从arr的left开始进行遍历。当copyArr[i-left]比copyArr[j-left]小时, arr[k] 等于 copyArr[i-left],此时k++,i++。当copyArr[i-left]比copyArr[j-left]大时,arr[k] 等于 copyArr[j-left],此时k++,j++。
    在这里插入图片描述
 /**
     * 归并排序
     * @param arr
     * @param n
     */
    public void mergeSort(E[] arr, int n){
        mergeSort(arr, 0 ,n-1);
    }
    /**
     * 递归使用归并排序,对arr[l,...,r]的范围进行排序
     * @param arr
     * @param left
     * @param right
     */
    private void mergeSort(E[] arr,int left , int right){
        if( left >= right){
        //递归到底的情况
            return;
        }

        int middle = (left+right)/2;
        mergeSort(arr,left,middle);
        mergeSort(arr,middle+1,right);
        //对于近乎有序的进行判断
        if(arr[middle].compareTo(arr[middle+1]) > 0 ){
            merge(arr,left,middle,right);
        }
        //end mergeSort
    }
    
 /**
     * 将arr[l,...,mid]和arr[mid_1,...,r]两部分进行归并
     * @param arr
     * @param left
     * @param middle
     * @param right
     */
    private void merge(E[] arr, int left,int middle, int right){
        //辅助空间,并进行赋值 :浅复制
        E[] copyArr = arr.clone();
        for(int i=left; i<=right;i++){
            copyArr[i-left] = arr[i];
        }

        //定义三个索引
        int i = left;
        int j = middle+1;
        int k;//归并索引,下一个需要考虑的位置
        for(k = left;k<=right; k++){
            //判断索引是否有效
            if(i > middle){
                //前面的子数组已归并完
                arr[k] = copyArr[j-left];
                j++;
            }else if(j>right){
                //后面的子数组已归并完
                arr[k] = copyArr[i-left];
                i++;
            }else if(copyArr[i-left].compareTo(copyArr[j-left]) <0){
                //前面的子数组和后面的子数组都没归并完
                arr[k] = copyArr[i-left];
                i++;
            }else{
                //copyArr[i-left].compareTo(copyArr[j-left]) >0
                arr[k] = copyArr[j-left];
                j++;
            }
        }
    }

可参考https://www.cnblogs.com/chengxiao/p/6194356.html(图示和解释很详细)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值