归并排序

归并排序分两种,自顶向下和自底向上:

一、自顶向下

这种方式的思路是,将数组两等分的递归拆成最小的数组(也就是1/0个元素),然后在一个一个的拼接起来。

相比于自底向上,这种是更容易理解的,因为拆分不需要我们手动进行。

    /**
     * 自顶向下的归并排序,用到的是递归
     * @param nums
     */
    public void mergeSortT2B(int[] nums,int left,int right){
        if(left==right) return;
        int mid = (left+right)/2;
        mergeSortT2B(nums,left,mid);    //先把左半边排好序
        mergeSortT2B(nums,mid+1,right); //再把右半边排好序
        merge(nums,left,mid,right); //左右合并
    }

    /**
     * 合并两个排序数组部分(left-mid)(mid+1,right)
     * @param nums
     * @param left
     * @param mid
     * @param right
     */
    public void merge(int[] nums,int left,int mid,int right){
        int length = right-left+1;
        int[] temp = new int[length];   //一个用来暂存排序数组的数组
        int cur = 0;    //排序数组指针
        int lcur = left;    //左边数组指针
        int rcur = mid+1;   //右边数组指针
        while(lcur<=mid && rcur<=right){
            if(nums[lcur]<nums[rcur]){
                temp[cur] = nums[lcur];
                lcur++;
            }else {
                temp[cur] = nums[rcur];
                rcur++;
            }
            cur++;
        }
        while(lcur<=mid){
            temp[cur] = nums[lcur];
            cur++;
            lcur++;
        }
        while(rcur<=right){
            temp[cur] = nums[rcur];
            cur++;
            rcur++;
        }
        if (length >= 0) System.arraycopy(temp, 0, nums, left, length);
    }

二、自底向上

这种其实比自顶向下少了一个拆分的步骤,直接从最小的开始合并,用的是迭代的方式。这样做就避免了递归开栈,少了更多资源消耗。

但是这种的问题就在于想着容易,不好写。

    /**
     * 自底向上的归并排序
     * @param nums
     */
    public void mergeSortB2T(int[] nums){
        int length = nums.length;
        for (int x=1;x<length;x+=x){    //每一次归并的数组大小x,从1开始
            for (int y = 0; y < length-x; y+=2*x) { //每两个数组的起始元素下标y
                merge(nums,y,y+x-1,Math.min(y+2*x-1, length-1));
            }
        }
    }

所以要借鉴别人的,一旦写出过一次,理解了思路,下一次自己写就好写了。

分两层循环,

  • 外层的x表示每一次归并的数组大小,从1开始,每次翻一倍
  • 内层的y表示每两个需要合并数组的起始位置的下标,每次加两倍的x。

三、性能测试

    public static void main(String[] args) {
        MergeSort mergeSort = new MergeSort();
        int[] nums1 = ArrayUtils.getRandomArray(1000000);
        int[] nums2 = ArrayUtils.getRandomArray(1000000);
        long start = System.currentTimeMillis();
        mergeSort.mergeSortT2B(nums1,0,nums1.length-1);
        long end = System.currentTimeMillis();
        System.out.println("自顶向下耗时:"+(end-start)+"ms");
        System.out.println();
        start = System.currentTimeMillis();
        mergeSort.mergeSortB2T(nums2);
        end = System.currentTimeMillis();
        System.out.println("自底向上耗时:"+(end-start)+"ms");
    }

获取两个大小相等的随机数组,观察其耗时。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值