归并排序 Java

来源:互联网 发布:玛丽王后知乎 编辑:程序博客网 时间:2024/06/05 07:21

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 当数据是基本有序的情况下,在合并的时候可以进行判断,如果前一个数组的最后一个元素比后一个数组的第一个元素还要小,那么就可以直接合并,无需比较了