解题思路

题目要求解题时间在1s内,那么就限定了排序算法范围在快排、堆排和归并排序之间,下面依次实现之;

快排

算法原理

快排采用了分治的思想:要对数组A进行排序,可以先将A分成两个子数组A1和A2,并同时保证A1中任一元素值小于A2中任一元素,然后对两子数组在重复此操作直到数组无法再进行分割,最后将各个子数组拼接起来便是一个有序数组了。用算法表述如下:

quickSort(A, p, r) {
    if (p < r) {
        q = partition(A, p, r);
        quickSort(A, p, q - 1);
        quickSort(A, q + 1, r);
    }
}

其中最关键的就是partion()方法了,它负责将一个数组A分成两个子数组A[p..q-1]和A[q+1..r],结果是A[p..q-1]中任一数值小于A[q+1..r]中任一数值,两子数组分界点便是A[q];借用《算法导论》中图示如下:

在partition()处理过程中将存在如下三个区:
图片说明

算法实现

public class Solution {
    public int[] MySort(int[] arr) {
        quickSort(arr, 0, arr.length - 1);
        return arr;
    }

    private void quickSort(int[] A, int p, int r) {
        if (p < r) {
            int q = partition(A, p, r);
            quickSort(A, p, q - 1);
            quickSort(A, q + 1, r);
        }
    }

    private int partition(int[] A, int p, int r) {
        int x = A[r];
        int i = p - 1;
        for (int j = p; j < r; j++) {
            if (A[j] <= x) {
                swap(A, ++i, j);
            }
        }
        swap(A, i + 1, r);
        return i + 1;
    }

    private void swap(int[] arr, int i, int j) {
        if (arr[i] != arr[j]) {
            arr[i] ^= arr[j];
            arr[j] ^= arr[i];
            arr[i] ^= arr[j];
        }
    }
}

归并排序

算法原理

与快排一样,归并排序同样利用分治思想:它先对数组A进行二分,直到不能分割为止,最后将得到各单调子数组(每个数组只包含一个数值,因此必然是单调的),最后将各单调子数组合起来即为排序后数组,用算法描述如下:

mergeSort(A, p, r) {
    if (p < r) {
        q = p + ((r - q) >> 1);
        mergeSort(A, p, q);
        mergeSort(A, q + 1, r);
        merge(A, p, q, r);
    }
}

再次借用《算法导论》图示进行说明:
图片说明
对于数组A[p,r]=[5,2,4,7,1,3,2,6],先将其进行二分,得到各单调子数组,也即最下面那行;然后通过归并操作(merge())不停的将两个单调数组合为一个,最终得到一个有序数组;
我们不难发现,最重要的就是merge()操作:它用来将两个单调数组(A[p..q]和A[q..r])合为一个单调数组A'[p..r];处理起来也很简单,只要新开辟一个数组与归并后数组大小一样,然后逐个比较两个单调数组,按比较的值从小到大放到新开辟数组中;

算法实现

public class Solution {
    public int[] MySort(int[] arr) {
        mergeSort(arr, 0, arr.length - 1);
        return arr;
    }

    private void mergeSort(int[] A, int L, int R) {
        if (L < R) {
            int M = L + ((R - L) >> 1);
            mergeSort(A, L, M);
            mergeSort(A, M + 1, R);
            merge(A, L, M, R);
        }
    }

    // 合并两单调数组(A[L..M]和A[M+1..R])为一个单调数组
    private void merge(int[] A, int L, int M, int R) {
        int[] tmp = new int[R - L + 1];
        int index = 0;
        int i = L, j = M + 1;
        while (i <= M && j <= R) {
            if (A[i] <= A[j]) {
                tmp[index++] = A[i++];
            } else {
                tmp[index++] = A[j++];
            }
        }
        while (i <= M) {
            tmp[index++] = A[i++];
        }
        while (j <= R) {
            tmp[index++] = A[j++];
        }

        for (int k = 0; k < tmp.length; k++) {
            A[L + k] = tmp[k];
        }
    }
}