快速排序

快速排序

在这里插入图片描述

简介

  1. 快速排序是一种基于分治法的排序方法,交换类排序
  2. 每一趟快排选择序列中任何一个元素作为枢轴(pivot)(通常选择第一个元素), 将序列中比枢轴小的元素都移动到枢轴前面, 比枢轴大的元素都移动到枢轴的后边

分治法

  1. 第一步首先将原问题分解成若干个子问题, 这个子问题只是原问题较小规模的实例
  2. 将解决这些子问题, 递归的求解各个子问题; 递归的边界就是问题规模足够小的时候, 可以直接求解

基本步骤

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

代码实现

def partition(r, left, right):
    i = left
    j = right
    while (i < j):
        while (i < j and r[i] <= r[j]):  # 右侧扫描
            j -= 1
        if i < j:
            r[i], r[j] = r[j], r[i]
            i += 1
        while (i < j and r[i] <= r[j]):  # 左侧扫描
            i += 1
        if i < j:
            r[i], r[j] = r[j], r[i]
            j -= 1
    return i  # 轴值的位置


def qsort(r, left, right):
    if left < right:
        pivot = partition(r, left, right)  # 一次划分
        qsort(r, left, pivot - 1)  # 递归对左侧子序列进行快速排序
        qsort(r, pivot + 1, right)  # 递归对右侧子序列进行快速排序


r = [7, 1, 5, 3, 6, 34, 22, 12, 43, 23]

qsort(r, 0, len(r) - 1)  # 必须要加一个 -1
print(r)

总结

分析

  1. 快速排序之所比较快,因为相比冒泡排序,每次交换是跳跃式的
  2. 每次排序的时候设置一个基准点,将小于等于基准点的数全部放到基准点的左边,将大于等于基准点的数全部放到基准点的右边。这样在每次交换的时候就不会像冒泡排序一样每次只能在相邻的数之间进行交换,交换的距离就大的多了。因此总的比较和交换次数就少了,速度自然就提高了
  3. 当然在最坏的情况下,仍可能是相邻的两个数进行了交换。因此快速排序的最差时间复杂度和冒泡排序是一样的都是O(n**2),它的平均时间复杂度为O(nlogn)

时间复杂度

  1. 快速排序最优的情况就是每一次Partition取到的元素都刚好平分整个数组, 时间复杂度为O(nlogn) ,待排序序列越无序,算法效率越高
  2. 快速排序最坏的情况就是每一次Partition取到的元素在一端,时间复杂度为O(n2),待排序序列越有序,算法效率越低(相当于每次都是将待排序列划分为1个关键字和剩余其他关键字,n个关键字需要划分n-1次,每次时间复杂度为O(n),所以最坏情况下时间复杂度为O(n2))

空间复杂度

  1. 由于快速排序是递归的,需要借助一个递归工作栈来保存每一层递归调用的必要信息,其容量应与递归调用的最大深度一致
  2. 最好情况下为 ⌈log2(n+1)⌉(每次partition都很均匀)递归树的深度O(logn)
  3. 最坏情况下,因为要进行n-1次递归调用,所以栈的深度为O(n)

稳定性

  1. 快速排序是不稳定的,是因为存在交换关键字
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值