Algorithms 之 归并排序

归并排序在平均、最好、最差的时间复杂度都是O(nlogn),所以是非常稳定的算法,然而在归并的过程中需要额外的空间开销,空间复杂度为O(n)。但目前的计算机内存、硬盘的空间都很大,相较于空间开销,更加注重于时间的开销,所以归并排序还是值得我们学习的。


一、算法思想
归并排序主要体现的是分治的思想,每次都将数列一分为二,当分到最底层时再层层回溯归并,最终将每层的有序子数列归并为完全有序数列。
1)如图,每一层都不断将数组一分为二,直到只有一个元素;

2)分别将[8,6],[2,3],[1,5],[7,4]各自为一组进行归并,得到有序子数列[6,8],[2,3],[1,5],[4,7];

3)将有序子数列[6,8],[2,3]为一组进行归并,得到新的有序子数列[2,3,6,8];将有序子数列[1,5],[4,7] 为一组进行归并,得到新的有序子数列[1,4,5,7] ;

4)将有序子数列[2,3,6,8]和[1,4,5,7]进行归并,得到最终有序数列[1,2,3,4,5,6,7,8]。

二、归并过程
1)首先开辟一个和原数组同样大小的空间,指针 k(即蓝色箭头)指向新的空间,指针 i 指向左有序子序列,指针 j 指向右有序子序列;

2)比较 arr[i] 和 arr[j] 的大小,在升序的情况下,若左子序列当前值大于右子序列当前值,即 arr[i] > arr[j],则把右子序列当前值赋给辅助空间当前值,即 aux[k] = arr[j],然后右子序列、辅助空间指针后移;

3)继续比较 arr[i] 和 arr[j],若左子序列当前值小于右子序列当前值,即 arr[i] < arr[j],则把左子序列当前值赋给辅助空间当前值,即 aux[k] = arr[i],然后左子序列、辅助空间指针后移,以此类推,至到排序结束。

三、代码实现

public class Merge{

    public int[] sort(int[] arr, int n) {
        mergeSort(arr, 0, n - 1);
        return arr;
    }

    //对arr[l,r]进行归并
    static void mergeSort(int[] arr, int l, int r){

        //当个数小于11时,采用插入排序
        if(r - l <= 10){
            insertion(arr, l, r);
            return;
        }

        int mid = (l + r) / 2;
        mergeSort(arr, l, mid);
        mergeSort(arr, mid + 1, r);

        //当左边最大的元素大于右边最小的元素时才需要进行归并
        if(arr[mid] > arr[mid + 1]){
            merge(arr, l, mid, r);
        }
    }

    //将arr[l, mid]和arr[mid+1, r]进行合并
    static void merge(int[] arr, int l, int mid, int r){
        //开辟辅助空间
        int[] aux = new int[r - l + 1];
        for (int i = l; i <= r; i++){
            aux[i - l] = arr[i];
        }

        int t = l;
        int p = mid + 1;
        for (int i = l; i <=r; i++){
            if(t > mid){                //左边的已经遍历完成
                arr[i] = aux[p - l];
                p++;
            } else if(p > r){           //右边的已经遍历完成
                arr[i] = aux[t - l];
                t++;
            } else if(aux[t - l] > aux[p - l]){
                arr[i] = aux[p - l];
                p++;
            } else {
                arr[i] = aux[t - l];
                t++;
            }
        }
    }

    //对arr[l,r]进行插入排序
    static void insertion(int[] arr, int l, int r){
        for (int i = l + 1; i <= r; i++){
            int copy = arr[i];
            int j;
            for (j = i; j - l > 0 && copy < arr[j - 1]; j--){
                arr[j] = arr[j - 1];
            }
            arr[j] = copy;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值