快速排序

来源:互联网 发布:网络主播套路 编辑:程序博客网 时间:2024/06/06 06:52

快速排序

快速排序的基本思想是通过划分子数组实现的,对于数组A[p…r],划分子数组后得到一个索引q,使得A[p…q-1]子数组的值都小于A[q],A[q+1…r]子数组的值都大于等于A[q]。子数组划分后,再通过相同的方法递归处理两个子数组,最终达到整个数组排序的目的。

快速排序伪代码

先看下伪代码:

quick_sort(A, p, r)  if (p < r)    int q = partition(A, p, r);    quick_sort(A, p, q - 1);    quick_sort(A, q + 1, r);

伪代码的思路很简单,快速排序最重要的是划分子数组,即partition的实现,先看下partition示意图

这里写图片描述


划分子数组过程中将数组分为四个区域,首先将A[r]=x选为主元,划分子数组结束后A[q]的值就是x,即将数组划分为小于x和不小于x的两个部分。

  • 区域1:这个区域的值小于x
  • 区域2:这个区域的值大于等于x
  • 区域3:这个区域的值和x大小是未知的,是将要消除的区域
  • 区域4:主元

划分子数组伪代码

划分子数组的过程即是消除区域3的过程,最终指针j等于r,看下partion的伪代码:

partition(A, p, r)  x = A[r]  i = p - 1  for j = p to r - 1    if A[j] < x        i = i + 1        exchange(A[i], A[j])  exchange(A[i+1], A[r])  return i + 1

根据quick_sort和partion的伪代码,很容易写出java代码:

public class QuickSort {    /**     * 快速排序     * @param arr 待排序的数组     * @param left 起始索引     * @param right 结束索引     */    public static void quickSort(int[] arr, int left, int right) {        if (left < right) {            int q = partition(arr, left, right);            quickSort(arr, left, q - 1);            quickSort(arr, q + 1, right);        }    }    /**     * 划分子数组,返回值为q,则arr[left...q-1]子数组的值都小于arr[q],     * arr[q+1...right]子数组的值都不小于arr[q]     * @param arr     * @param left     * @param right     * @return     */    private static int partition(int[] arr, int left, int right) {        int i = left - 1;        int x = arr[right];        for (int j = left; j < right; j++) {            if (arr[j] < x) {                i++;                exchange(arr, i, j);            }        }        exchange(arr, i + 1, right);        return i + 1;    }    private static void exchange(int[] arr, int i, int j) {        int tmp = arr[i];        arr[i] = arr[j];        arr[j] = tmp;    }}

复杂度分析

空间复杂度O(1)

快速排序的时间性能取决于划分的性能,如果每次划分都将子数组划分为差不多相等的两部分,那么排序性能会非常好,此时时间复杂度为O(nlgn)

如果每次划分都将数组划分为大小为n-1和0的子数组时,此时排序性能会非常差,时间复杂度为O(n2)

最坏时间复杂度O(n2)

最好时间复杂度O(nlgn)

平均时间复杂度O(nlgn)