归并排序 Java

1 排序原理

归并排序是分治法的一个典型应用,简单来说,归并排序分为两部分,第一部分是拆,就是将数组的长度一层一层往下拆,第二部分就是将拆好的一个一个相邻的数据进行合并,在这一步里面我们进行排序。整体思想其实非常简单 

2 时间复杂度

O(logn*n)
正如其他的高级排序算法一样,归并排序其实也就是减少我们进行排序的重复操作。拆分的时候,采用二分的方式,所以有logn层,而每层比较的次数就是n喽,所以其时间复杂度为O(logn*n),
其实仔细想一想,所有的排序算法其本质差不多啦,就是较少重复操作,而如何减少重复操作呢,就是让我之前的操作对后序操作产生影响,这一点,归并排序比较明显,在其合并的时候,我合并的一个一个相邻的子数组,其实其内部是有序的,这也就是为什么归并排序效率高的原因了
    额外说一句,外排序的基础也是归并排序 

3 算法实现

/**
 * 归并排序--分为两部分 拆:递归拆 合:进行排序
 * 
 * @author xld
 *
 */
public class MergeSort {

    public static void sort(int[] arr) {
        int n = arr.length;
        sort(arr, 0, n - 1);
    }

    /**
     * 注意 这里的数组的取值范围为[l,r],也就是说,左右下标都可以取到
     * 
     * @param arr
     *            数组
     * @param l
     *            数组左下标
     * @param r
     *            数组右下标
     */
    private static void sort(int[] arr, int l, int r) {
        // 递归出口
        if (l >= r) {
            return;
        }
        int mid = (l + r) / 2;
        sort(arr, l, mid);
        sort(arr, mid + 1, r);
        merge(arr, l, mid, r);
    }

    /**
     * 合:真正将数据进行排序 将两个相邻的数组进行合并 是相邻的哦
     * 
     * @param arr
     * @param l
     * @param mid
     * @param r
     */
    private static void merge(int[] arr, int l, int mid, int r) {
        // 创建辅助数组
        int[] aux = new int[r - l + 1];
        // 辅助数组下标
        int auxIndex = 0;
        // 初始化辅助数组
        for (int i = l; i <= r; i++) {
            aux[auxIndex++] = arr[i];
        }
        // 左数组的下标索引
        int leftIndex = l;
        // 右数组的下标索引
        int rightIndex = mid + 1;
        for (int i = l; i <= r; i++) {
            // 如果左半部分元素已经全部处理完毕
            if (leftIndex > mid) {
                arr[i] = aux[rightIndex-l];
                rightIndex++;
            } else if (rightIndex > r) {
                arr[i] = aux[leftIndex-l];
                leftIndex++;
                // 小于等于 这个是归并排序稳定性的关键哦!
            } else if (aux[leftIndex-l] <= aux[rightIndex-l]) {
                // 当然也可以将两句直接写成arr[i]=aux[leftIndex++];我这里是为了好理解
                arr[i] = aux[leftIndex-l];
                leftIndex++;
            } else {
                arr[i] = aux[rightIndex-l];
                rightIndex++;
            }
        }
    }

    /**
     * 测试
     * @param args
     */
     public static void main(String[] args) {

            int[] arr = {10,9,8,7,6,5,4,3,2,1};
            MergeSort.sort(arr);
            for( int i = 0 ; i < arr.length ; i ++ ){
                System.out.print(arr[i]);
                System.out.print(' ');
            }
            System.out.println();
        }
}

4 优化

1 当数据量比较小的时候,可以采用插入排序进行优化,这是因为小的数据量,进行多次递归的消耗就犯不上了
2 当数据是基本有序的情况下,在合并的时候可以进行判断,如果前一个数组的最后一个元素比后一个数组的第一个元素还要小,那么就可以直接合并,无需比较了
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值