排序算法之快速排序

快速排序算法实现,欢迎交流,指正错误。

1. 快速排序

快速排序(Quicksort)是对冒泡排序的一种改进。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列

采用了分治的思想:

该方法的基本思想是:

  • 先从数列中取出一个数作为基准数。
  • 分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
  • 再对左右区间重复第二步,直到各区间只有一个数。

1.1. 复杂度分析

  • 时间复杂度(平均):O(nlogn)
  • 时间复杂度(最坏):O(n^2) (退化为冒泡排序)
  • 时间复杂度(最好):O(nlogn)
  • 空间复杂度:O(nlogn)
  • 稳定性:不稳定

2. 快速排序实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
 * 快速排序的实现
 */
public void quickSort(int[] arr) {
    if (null == arr || 1 >= arr.length) { return; }

    quickSort(arr, 0, arr.length - 1);
}

private void quickSort(int[] arr, int start, int end){
    if (start >= end) { return; }
	// 寻找左右划分的边界
    int boundary = findBoundary(arr, start, end);
	// 左边使用快排
    quickSort(arr, start, boundary - 1);
    // 右边使用快排
    quickSort(arr, boundary + 1, end);
}

private int findBoundary(int[] arr, int l, int r){
    int pivot = arr[start]; // 以第一个元素作为基准
   
    while (l < r){
        // 最右边开始找, 找到第一个比pivot小的数
        while (l < r && pivot <= arr[r]) { r--; }
        arr[l] = arr[r];
        // 最左边开始找,找到以一个比pivot大的数
        while (l < r && arr[l] <= pivot) { l++; }
        arr[r] = arr[l];
    }
    arr[l] = pivot;
    // 返回边界值
    return l;
}

3. 快速排序的应用

题目:

有一个整数数组,请你根据快速排序的思路,找出数组中第K大的数。

给定一个整数数组a,同时给定它的大小n和要找的K(K在1到n之间),请返回第K大的数,保证答案存在。

思路:

一般top K问题适合用堆排序解决,但此处要求使用快速排序的思路解决。

我们知道快速排序每经历一次排序后(降序排序),pivot所处的位置是固定的,因为pivot前面的数都不小于它,而pivot后面的数都不大于它,因此经过K次排序后的结果即为第K大。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public int findKth(int[] a, int n, int K) {
    // write code here
    if(a == null || a.length == 0) return -1;
    return quickSort(K, a, 0, n-1);
}

private int quickSort(int K, int[] a, int start, int end){
	// 寻找边界
    int boundary = findBoundary(a, start, end);
    // 边界值 + 1 == K,找到第K大的数
    if(boundary + 1 == K)
        return a[boundary];
    // 边界值 + 1 < K,应在右半部分找第K大的数
    else if(boundary + 1 < K)
        return quickSort(K, a, boundary + 1, end);
    // 边界值 + 1 > K,应在左半部分找第K大的数
    else 
        return quickSort(K, a, start, boundary - 1);
}

private int findBoundary(int[] a, int start, int end){
    int pivot = a[start];
    while(start < end){
        while(start < end && a[end] <= pivot) end--;
        a[start] = a[end];
        while(start < end && a[start] >= pivot) start++;
        a[end] = a[start];
    }
    a[start] = pivot;
    return start;
}
0%