算法之路-快速排序

143 阅读2分钟

这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战

快速排序经常会出现在面试题中,甚至有个简称叫快排。这个待遇是其他排序算法不曾有过的待遇,包括网友的讨论都是默认快速排序。其实上一篇文章所提及的归并排序的性能很好而且很稳定,唯一的缺点是需要一个额外的O(n)的空间开销。快排也是分治思想的一种应用,当可以把问题一分为二解决时,问题的复杂度会大大降低。

快速排序还有一个比较大的优势是:算法的实现相对简单。

  • 从数组中挑出一个元素作为基准值,可以任意选择。
  • 遍历一下数组,比基准值小的放左边,比基准值大的放右边,完成之后基准值这个位置就已经排序了。
  • 基准值左右两边的数组各自递归执行一下以上的过程

有人说这个基准值的选择有什么讲究吗?没有,因为需要做交换,你也不可能正好选中那个中间的值。所以我建议直接选首位的元素就好了。

复杂度与适用场景

复杂度想必已经很清楚了,首先有一个比较和交换,要遍历整个列表所以是个O(n),然后分治会有一个O(logn),所以最终的复杂度为O(nlogn)。但极少的概率下会产生O(n^2)的最差情况,当数组完全有序时才会发生。应用场景方面就太多了,很多开发者应对简单排序时首选都是快速排序。

实现

public int[] quickSort(int[] arr, int left, int right) {
        if (left < right) {
            int partitionIndex = partition(arr, left, right);
            quickSort(arr, left, partitionIndex - 1);
            quickSort(arr, partitionIndex + 1, right);
        }
        return arr;
    }
    
 public int partition(int[] arr, int left, int right) {
        int pivot = left;
        int index = pivot + 1;
        for (int i = index; i <= right; i++) {
            if (arr[i] < arr[pivot]) {
                swap(arr, i, index);
                index++;
            }
        }
        swap(arr, pivot, index - 1);
        return index - 1;
    }
 public void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }