金九银十之快速排序

147 阅读1分钟

什么是快速排序

快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为较小和较大的2个子序列,然后递归地排序两个子序列。 步骤为: 挑选基准值:从数列中挑出一个元素,称为“基准”(pivot), 分割:重新排序数列,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基准后面(与基准值相等的数可以到任何一边)。在这个分割结束之后,对基准值的排序就已经完成, 递归排序子序列:递归地将小于基准值元素的子序列和大于基准值元素的子序列排序。 递归到最底部的判断条件是数列的大小是零或一,此时该数列显然已经有序。

选取基准值有数种具体方法,此选取方法对排序的时间性能有决定性影响。

时间,空间

时间:O(NlogN)

空间:O(logn)

代码实现

public static void quickSort(int[] arr) {
    if (arr == null || arr.length < 2) {
        return;
    }
    quickSort(arr, 0, arr.length - 1);
}

public static void quickSort(int[] arr, int L, int R) {
    if (L < R) {
        swap(arr, L + (int) (Math.random() * (R - L + 1)), R);
        int[] p = partition(arr, L, R);
        quickSort(arr, L, p[0] - 1);
        quickSort(arr, p[1] + 1, R);
    }
}

public static int[] partition(int[] arr, int L, int R) {
    int less = L - 1;
    int more = R;
    while (L < more) {
        if (arr[L] < arr[R]) {
            swap(arr, ++less, L++);
        } else if (arr[L] > arr[R]) {
            swap(arr, --more, L);
        } else {
            L++;
        }
    }
    swap(arr, more, R);
    return new int[]{less + 1, more};
}
public static void swap(int[] arr, int i, int j) {
  int tmp = arr[i];
  arr[i] = arr[j];
  arr[j] = tmp;
}

执行过程

快速排序.2021-09-26 23_27_00.gif

是否稳定

不稳定

快速排序是荷兰国旗问题的partition以及将这个过程重复递归的实现,partition无法保证稳定性,可以举例实验一下[7,7,1,4,9,7],对该数组进行partition以后,7的次序已经被打乱了,所以快速排序并不具有稳定性。