O(nlogn)排序之归并排序

1. 自顶向下递归

将数组分组,在将每组进行分组,一直分下去,最后分道每组一个元素,这一个元素可以看作是有序的。然后向上归并。然后上一组在排序。排完序,在归并。一直到第一轮。

如数组:1 2 3 4 5 6 7 8

第一轮: 1 2 3 4 | 5 6 7 8 分成两组
第二轮: 1 2 | 3 4 | 5 6 | 7 8 每组在分成两组
第三轮: 1 | 2 | 3 | 4 | 5 | 6| 7 | 8 每组在分成两组

每轮分组的时间复杂度都为O(logn), 而每组的排序的时间复杂度为O(n), 综合时间复杂度为O(nlog), 每组排完序之后,向上归并。分组的过程是递归的

需要注意的地方

 1. 归并排序是以空间换时间的方式排序。除了原数组外,还的为每一个分组提供一个辅助数组。
 2. 边界问题,要规定好左中右三个边界,即是三个数组的索引值。这里指定l=0(left), mid 数组中间位置的前一个位置。r=数组的长度-1(right)
 3. 归并排序最重要的地方是制定三个索引值,即每组的的起始索引,为i,j。还有就是当前分组的父分组的起始索引k。

代码:

package com.fgy.learn;

/**
 * Created by snow_fgy on 2019/4/5.
 */
public class MergeSort2 {

    //获取随机数组
    public int[] getReadom(int n, int random) {

        int [] a = new int[n];
        for (int i = 0; i < n; i++){
            a[i] = (int) (Math.random() * random);
        }
        return a;

    }

    public void mergeSort(int [] arr) {
        mergeSortInner(arr, 0, arr.length - 1);
//        for (int i : arr) {
//            System.out.print(i + " ");
//        }
//        System.out.println();
    }

    //进行递归后分组,分组完毕后进行归并
    private void mergeSortInner(int [] arr, int l, int r) {

        //做左边界已经大于等于一个分组的有边界了,证明现在的分组为一个元素,则往下已经分不了组和归并了,则排序完成。
        /**

		  if (r-l <= 10) {
            insertSort2(arr);
            return;
        }

        /
        if (l >= r) {
            return;
        }
        //获取中间位置
        int mid = (l + r) / 2;
        mergeSortInner(arr, l, mid);
        mergeSortInner(arr, mid + 1, r);
        //分组完毕,开始归并
        /**优化:
        *if(arr[mid] > arr[mid+1]) {
        *            merge(arr,l, mid, r);
        *}
        */
        merge(arr,l, mid, r);


    }

    private 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 i = l;
        int j = mid + 1;

        for (int k = l; k <= r; k++) {

            //判断边界
            if (i > mid) {
                arr[k] = aux[j-l];
                j++;
            } else if (j > r) {
                arr[k] = aux[i-l];
                i++;
            } else if (aux[i-l] < aux[j-l]) {
                arr[k] = aux[i-l];
                i++;
            } else {
                arr[k] = aux[j-l];
                j++;
            }
        }
    }

    public void shellSort(int [] a){
        int temp;
        int j;

        for (int increment = a.length / 2; increment > 0; increment /= 2) {

            for (int i = increment; i < a.length; i ++) {
                temp = a[i];

                for (j = i - increment; j >= 0; j -= increment) {

                    if (temp < a[j]) {
                        a[j + increment] = a[j];
                    }else {
                        break;
                    }
                }
                a[j + increment] = temp;

            }
        }

//        for (int i : a) {
//            System.out.print(i + " ");
//        }
//        System.out.println();

    }

    public void insertSort2(int [] a){
        for (int i = 1; i < a.length; i++) {
            int temp = a[i];
            for (int j = i; j > 0 && a[j] > a[j-1]; j--) {
                a[j] = a[j-1];
            }
            a[i] = temp;
        }
//        for (int i : a) {
//            System.out.print(i + " ");
//        }
//        System.out.println();

    }

    public static void main(String[] args) {

        MergeSort2 sort = new MergeSort2();
        Sort sort1 = new Sort();
        int[] arr = sort.getReadom(1000, 10000);
        int[] arr2 = arr.clone();
        int[] arr3 = arr.clone();

        long time1 = System.currentTimeMillis();
        sort.mergeSort(arr);
        long time2 = System.currentTimeMillis();
        System.out.println("mergeSort: " + (time2 - time1) / 1000.0 + "s");
        sort.insertSort2(arr2);
        long time3 = System.currentTimeMillis();
        System.out.println("insertSort2: " + (time3 - time2) / 1000.0 + "s");
        sort.shellSort(arr3);
        long time4 = System.currentTimeMillis();
        System.out.println("shellSort: " + (time4 - time3) / 1000.0 + "s");

    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值