数据结构笔记:快速排序

原文地址

分类目录——数据结构笔记

  • 建议必须要掌握的,用的比较多。

  • 理解1

    每次取出第1个元素,剩余元素算作一个序列,使用两个指针分置两端,姑且吧左端称之为小指针,把右端称之为大指针,作用就是为了给第1个元素找的合适的位置。比较小指针指向值与第1个元素,如果比第1元素小说明符合要求,继续后移去判断下一个,如果不满足要求,即小指针的值比第1元素大了,停住小指针,去最右端看大指针,如果大指针指的值比第1元素值大,符合要求,大指针前移再判断,如果不满足要求,也就是大指针指的值比第1元素值小了,停住大指针。这时候两个指针都停住了,那么只要置换两个指针当前的指向值,两个就都满足要求了,然后继续从小指针开始比较。待到小指针与大指针重合了,那么这时候小指针(也可以说是大指针,因为重合了)

    第1个元素找到位置后,把序列按它分成前后两部分,分别对着两部分在进行上述操作

    直到最后每部分只有一个元素

  • 理解方式2

    代码实现起来更容易

    取第1个元素定义为mid_value,首尾定义两个指针,左首姑且叫它小指针(这是它指向第一个位置——mid_value),右首姑且叫它大指针。小指针在mid_value上,去动右侧大指针,如果比mid_value大,满足条件,继续向前查询,如果查询到小于min_value,与小指针的值(mid_value)交换,此时大指针指向mid_value,去动小指针,满足条件(比min_value小),右移继续去查询,如果不满足(比mid_value大),与大指针对应值(mid_value)交换,知道大小指针重合,mid_value也就在了它应该所在的中间位置。

  • 实现

    通过理解2的方式实现

    def quicksort(alist, begin, end):
        if begin>=end:
            return
        mid_value = alist[begin]
        low = begin
        high = end
    
        # 对确定本轮迭代中mid_value在alist[begin: end]中的位置
        while low < high:
            # 左移
            while low < high and alist[high] >= mid_value:
                # 在思想上,将mid_value就当做一个分界线,如果有相同的mid_value,尽量把这些相同值放在同一侧,这里选择了放在左侧
                high -= 1
            alist[low] = alist[high]
            # low += 1  # 宁可多加一步比较,写在这里会让小指针与大指针错过
            # 右移
            while low < high and alist[low] < mid_value:
                low += 1
            alist[high] = alist[low]
            # high -= 1
        # 从循环退出时,low=high
        alist[low] = mid_value
    
        # 对左右两部分再递归进行快速排序
        # quicksort(alist[:low])    # 这么传参是不对滴,切片会生成一个新的list,这样只是对新的list做排序,不会返回到原list中
        # quicksort(alist[low+1:])  # 所以对函数进行了整体改动,加入了传入了其实终止值
    
        # 对mid_value(确定位置后)左边进行quicksort
        quicksort(alist, begin, low-1)
        # 对mid_value(确定位置后)右边进行quicksort
        quicksort(alist, low+1, end)
    
  • 测试

    if __name__ == '__main__':
        ll = [3,6,2,4,7,5,8,1,0,9]
        print(ll)
        quicksort(ll, 0, len(ll)-1)
        print(ll)
    
  • 时间复杂度

    • 最优时间复杂度:O(nlogn)
    • 最坏时间复杂度:O(n^2)
    • 稳定性:不稳定

    从一开始快速排序平均需要花费O(n log n)时间的描述并不明显。但是不难观察到的是分区运算,数组的元素都会在每次循环中走访过一次,使用O(n)的时间。在使用理解2的版本中,这项运算也是O(n)。

    在最好的情况,每次我们运行一次分区,我们会把一个数列分为两个几近相等的片段。这个意思就是每次递归调用处理一半大小的数列。因此,在到达大小为一的数列前,我们只要作log n次嵌套的调用。这个意思就是调用树的深度是O(log n)。但是在同一层次结构的两个程序调用中,不会处理到原来数列的相同部分;因此,程序调用的每一层次结构总共全部仅需要O(n)的时间(每个调用有某些共同的额外耗费,但是因为在每一层次结构仅仅只有O(n)个调用,这些被归纳在O(n)系数中)。结果是这个算法仅需使用O(n log n)时间。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BBJG_001

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值