排序---归并排序

106 阅读1分钟

思路:(1)数组左半个有序(递归),在右半个位置上有序(递归),让左右所有都有序。merage

image.png

(2)设置一个辅助数组存储有序数组

(3)谁数值小就将其拷贝到辅助数组中---直到所有数值拷贝结束

image.png

时间复杂度:O(N),指针不会回退。

  • 使用递归实现
    //递归方法实现
    public static void mergeSort1(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        } 
        process(arr, 0, arr.length - 1);
    }
   
    //arr[L...R]范围上,变成有序的
    //L...R N   T(N) = 2*T(N/2) + O(N) ->
    public static void process(int[] arr, int L, int R) {
        if (L == R) {
            return;
        }
        int mid = ((R - L)>>1) + L;
        process(arr,L,R);//
        process(arr,mid + 1, R);//
        merge(arr, L ,mid, R);//
    }
    public static void merge(int[] arr, int L, int M, int R) {
        int[] help = new int[R - L + 1];
        int i = 0;
        int p1 = L;//设置左边界
        int p2 = M + 1;//设置右边界
        while (p1 <= M && p2 <= R) {//不越界的情况下
            help[i++] = arr[p1] <= arr[p2] ? arr[p1++]: arr[p2++];
        }
        //如果越界要么左,要不就是右,只有两者中的一个情况
        while (p1 <= M) {//p2越界
            help[i++] = arr[p1++];
        }
        while (p2 <= R) {//p1越界
            help[i++] = arr[p2++];
        }
        for (int i = 0; i < help.length; i++) {
            //最后的代码拷贝到arr中
            arr[L + i] = help[i];
        }
    }
}

拓展:比较归并排序与一般排序的优点

O(N^2)要比O(N*logN)优势:大量比较行为浪费空间

每次都可以调整步场来排序相邻的数顺序,这个过程(调整步长)为O(logN) ,随后相邻两组的数据排序为O(N)

so --- 总体的复杂度为:O(N)* O(logN)

  • 非递归实现

image.png

    if (arr == null || arr.length < 2) {
        return;
    }
    int N = arr.length;//总长
    //步长
    int mergeSize = 1;
    while (mergeSize < N) {//logN
        //当前左组的第一个位置
        int L = 0;
        //0...
        while (L < M) {
            // L...M 左组(mergeSize)
            int M = L + mergeSize - 1;//M到达右组的第一个位置
            if (M >= N) {//右组的长度不够就跳出来
                break;
            }
            //L...M  M+1...R(mergeSize)
            int R = Math.min(M + mergeSize, N - 1);//右组可以到达最以后的位置
            //不能超过N-1
            merge(arr, L, M, R);//
            L = R + 1;//左组来到下一个R+1的位置
        }
        if (mergeSize > N /2) {//防止溢出
            break;
        }
        mergeSize >> 1;//步长*2,不超过N就继续
    }
}