【python算法系列二】快速排序算法

本文详细介绍了快速排序算法的工作原理、时间复杂度和优化策略。通过实例展示了基础版和‘原地’版快速排序的Python实现,以及优化过程中如何减少空间需求。快速排序是一种高效的排序算法,平均时间复杂度为O(nlgn),但在最坏情况下可能达到O(n2)。文章还探讨了其不稳定性以及在适当条件下速度优于归并排序和堆排序的情况。
摘要由CSDN通过智能技术生成

快速排序的思想是:取数组中的一个数作为基准值,把所有小于基准值的数都放在它的一侧,再把所有大于基准值的数都放在它的另一侧。随后,对基准值左右两侧的数组分别进行快速排序。由此可以看出,快速排序的整个排序过程也是递归进行的。

快速排序的平均时间复杂度是 O(nlgn),最好情况下的时间复杂度是 O(nlgn)。最坏情况下,快速排序的时间复杂度可能退化成 O(n2),但这种情况很少见。它的空间复杂度是 O(nlgn)。它是一个不稳定的排序算法。如果使用得当,快速排序的速度可以达到归并排序和堆排序的数倍,所以快速排序是一种极其常用的算法。

以升序排序为例,快速排序的流程如下:

图 1:快速排序

一般情况下,我们取数组的第一个数作为基准进行快速排序。在第一步中,基准数为 5。可以看出,在第二行的数组中,比 5 小的元素:3、4、1、2,都被置于 5 的左侧,而比 5 大的元素则被置于 5 的右侧。这时,元素 5 在有序数组中的位置就确定了。

第三行中,我们再取左右两个无序数组的第一个数 3 和 6,分别作为它们的基准数,然后再次对数组进行分拆。分拆结束之后,3 和 6 在有序数组中的位置也确定了。

接下来,继续处理分拆出来的 4 个子数组:[1,2]、[4]、[]、[8,7]。其中,一个子数组只剩一个数,一个为空。这意味着 [4] 与 [] 已经完成了对自己的快速排序。而其他的两个子数组则需继续处理。全部处理完毕后,我们将得到一个完整的有序数组。

可以看出,快速排序也是通过这样的分治思想来排序的。关于它的分治思想我们之后会继续讲解。 

快速排序代码(基础版)

nums = [5,3,6,4,1,2,8,7]
def QuickSort(num):
    if len(num) <= 1: #边界条件
        return num
    key = num[0] #取数组的第一个数为基准数
    llist,rlist,mlist = [],[],[key] #定义空列表,分别存储小于/大于/等于基准数的元素
    for i in range(1,len(num)): #遍历数组,把元素归类到3个列表中
        if num[i] > key:
            rlist.append(num[i])
        elif num[i] < key:
            llist.append(num[i])
        else:
            mlist.append(num[i])
    return QuickSort(llist)+mlist+QuickSort(rlist) #对左右子列表快排,拼接3个列表并返回
print(QuickSort(nums))

运行程序,输出结果为:

[1,2,3,4,5,6,7,8]

在 QuickSort( ) 函数中,首先是边界条件:如果传入函数的列表长度小于等于 1,那么这一段列表必定是有序的,可以直接返回。如果不满足边界条件,则继续执行函数。先用 key 存储基准值,再定义 3 个列表存储小于基准数的元素 llist,大于基准数的元素 rlist 和等于基准数的元素 mlist。由于接下来 for 循环的范围不包括列表中的第一个数,所以对 mlist 初始化时,多加一个初始元素 key。

接下来的 for 循环把数组内的元素分别归入 3 个列表中。随后,再次调用 QuickSort( ) 函数,对 llist 和 rlist 进行排序。这样,llist 和 rlist 就是有序的了,而 mlist 内的元素刚好处于它们中间的连接部分。所以,排序完成后,把 llist、mlist、rlist 按顺序拼接到一起并输出。

这是实现快速排序的一种方式。但是,这样实现快速排序需要额外开辟空间给用于归类的列表。并且,相似的思路应用于其他的编程语言时效率较低。那么,该如何优化这个算法,使得数组可以原地排序呢?

我们需要优化的是把基准值移动到正确位置的那一部分代码。具体的移动流程如下:

我们用一个变量存储基准值。然后,再使用两个指针,一个从左往右遍历,一个从右往左遍历。开始遍历时,可以把基准值在数组中的位置,也就是第一个元素,视作一个没有元素的空位。

1

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值