快速排序的详细执行流程

快速排序是一种非常常用的排序算法,由于其平均时间复杂度绝大多数时候是O(logn),并且是一种原地排序的算法,所以在面对大数据量的排序需求时,是我们的常用选择。
快速排序的基本思想是这样的:从待排序数据集中找到一个pivot(分区点),之后将小于pivot的数据移动到pivot的左边,将大于pivot的数据移动到pivot的右边。重复该动作,直到pivot左右的数据集大小为1后终止。这个算法最核心的部分是分区点的选择。为了保证原地排序,分区函数不能引入额外空间。
看代码的时候,有一个点需要注意,快速排序会进行多轮比较,每次比较,左右子区间只是大概的有序,并不会一轮快排就直接有序了,不是这样的。
本来想描述一下过程,但是想了想,程序员还是看代码来的更直接一点,没几行,大家看看代码吧,多看几遍,看不懂就debug。说实话,快排我写过好多次了,但是过几天不写就又忘了。不要去记代码,记不住的。还是要理解算法实现的思想。
先贴一下java代码的实现

class QuickSortSolution {

    // A utility function to swap two elements
    static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

    private static void quickSortC(int[] a, int p, int r) {
        if (p >= r) {
            return;
        }
        int q = partition(a, p, r);
        quickSortC(a, p, q - 1);
        quickSortC(a, q + 1, r);
    }

    public static int partition(int[] a, int start, int end) {
        int pivot = a[end];
        int i = start;
        for (int j = start; j < end; j++) {
            //步骤一:如果a[j]小于pivot时,a[i]和a[j]交换元素,单看这一步其实不好理解是在干啥,我们需要结合着其他几个步骤看,就容易理解了,步骤一和步骤二是将小于pivot的元素移动到pivot的左边
            if (a[j] < pivot) {
                //步骤二
                swap(a, i, j);
                //步骤三
                i = i + 1;
            }
        }
        //步骤四:将a[i]和pivot交换位置,在步骤三将i + 1了,所以此时pivot左边都是小于pivot的元素,pivot右边都是大于pivot的元素了。之后,递归重复以上步骤,直到pivot左右的元素个数都为1为止
        swap(a, i, end);
        return i;
    }

    public static void main(String[] args) {
        int[] arr = {10, 7, 8, 9, 1, 5};
        int n = arr.length;

        quickSortC(arr, 0, n - 1);
        System.out.println(Arrays.toString(arr));
    }
}

分区函数的写法非常巧妙,建议大家使用IDE一边调试一边观察数据集的运转流程,调试几遍就能理解,不要凭空去想,否则一会就蒙了。
时间复杂度分析
快排的时间复杂度,取决于分区函数的实现。按照上面的实现过程,如果每次都取最后一个元素作为pivot,并且每次分区都可以将数组平均分成相同的2份。快排的时间复杂度和归并是一样的,都是O(nlogn)。但是,我们无法做到一定均分。所以,快排的时间复杂度有可能退化为O(n²)。但是有很多种办法,可以避免快排退化为O(n²)。
空间复杂度分析
时间复杂度是O(1)。
原地排序分析
原地排序
稳定排序分析
因为分区的过程涉及交换操作,如果数组中有两个相同的元素,比如序列 6,8,7,6,3,5,9,4,在经过第一次分区操作之后,两个 6 的相对先后顺序就会改变。所以,快速排序并不是一个稳定的排序算法。
第一次分区,第一个6会和3发生交换,所以2个6的相互顺序发生了变化。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值