Python3实现快速排序

原理思路

快速排序也是分而治之思想的典范,通过递归解决问题。思路:1. 找到简单的基线条件(递归出口);2. 确定如何缩小问题的规模,使其符合基线条件。
详细的原理可以参考 这篇文章坐在马桶上看算法:快速排序
步骤归纳:

  1. 排序数组为collection,游标left从a的最左边开始,游标right从最右边开始
  2. 把pivot记为数组第一个数(即collection[left]),作为数组左右的分界值
  3. 从右边开始向左移动游标(right = right - 1)直到找到第一个小于pivot的数,存储在collection[left]当中
  4. 从左边开始向右移动游标(left = left + 1)直到找到第一个大于pivot的数,存储在collection[right]当中
  5. 重复上述两步直到两个游标相遇
  6. 将pivot放置到collection[left]位置上
  7. 随后递归地将pivot左右两部分分别排序!(递归)
    核心思想:每次选取一个基准值,找到其位置,其他数如果大于基准值,放在基准值左侧,如果大于基准值,放在基准值右侧。

代码实现

通用版本

def quick_sort(collection, low, high):
    # 快速排序
    if low >= high:
        return collection
    else:
        pivot = collection[low]    # 把第一个作为基准值
        left = low
        right = high
        while left < right:
            while left < right and collection[right] >= pivot:
                right -= 1    # 右边的哨兵左移一个
            collection[left] = collection[right]
            while left < right and collection[left] <= pivot:
                left +=1    # 左边的哨兵右移一个
            collection[right] = collection[left]
        collection[right] = pivot    # 两个哨兵相遇时则说明找到基准值的位置
        quick_sort(collection, low, left-1)    # 递归左半部分
        quick_sort(collection, left+1, high)    # 递归右半部分
        return collection

if __name__ == '__main__':
    collection = list(map(int, input().split()))
    print('排序前:', end='')
    for i in collection:
        print(i, end=' ')
    collection = quick_sort(collection, 0, len(collection)-1)
    print('\n排序后:', end='')
    for i in collection:
        print(i, end=' ')

实战中的版本

import random


def quick_sort_random_pivot(collection, low, high):
    # 快速排序
    if low >= high:
        return collection
    else:
        rand = random.randint(low, high)
        collection[rand],collection[low] = collection[low], collection[rand]    # 随机取一个作为基准值
        pivot = collection[low]
        left = low
        right = high
        while left < right:
            while left < right and collection[right] >= pivot:
                right -= 1    # 右边的哨兵左移一个
            collection[left] = collection[right]
            while left < right and collection[left] <= pivot:
                left +=1    # 左边的哨兵右移一个
            collection[right] = collection[left]
        collection[right] = pivot    # 两个哨兵相遇时则说明找到基准值的位置
        quick_sort_random_pivot(collection, low, left-1)    # 递归左半部分
        quick_sort_random_pivot(collection, left+1, high)    # 递归右半部分
        return collection

if __name__ == '__main__':
    collection = list(map(int, input().split()))
    print('排序前:', end='')
    for i in collection:
        print(i, end=' ')
    collection = quick_sort_random_pivot(collection, 0, len(collection)-1)
    print('\n排序后:', end='')
    for i in collection:
        print(i, end=' ')

Pythonic版本

def quick_sort_pythonic(collection):
    # 快速排序
    length = len(collection)
    if length <= 1:
        return collection
    else:
        pivot = collection[0]    # 取第一个数作为基准值
        left = [element for element in collection[1:] if element <= pivot]
        right = [element for element in collection[1:] if element > pivot]
        return quick_sort_pythonic(left) + [pivot] + quick_sort_pythonic(right)

if __name__ == '__main__':
    collection = list(map(int, input().split()))
    print('排序前:', end='')
    for i in collection:
        print(i, end=' ')
    collection = quick_sort_pythonic(collection)
    print('\n排序后:', end='')
    for i in collection:
        print(i, end=' ')

小结

三种版本里面,版本2是随机选取基准值,更加推荐这个版本。对于pythonic的版本,这个版本看着非常直观,可以很好的理解快速排序的思想,不过它的时间复杂度虽然和其他两个版本一样,不过实际运行过程中,pythonic版本的耗时会比版本1慢一些,同时也会增加更多的空间开销,因为有切片。面试时推荐用版本1,如果面试python可以用版本3,加分项。当然理解了思想,两者都能写出来最好!
这三种版本的最坏时间复杂度都是O(n2),最好时间复杂度和平均时间复杂度是O(nlogn),空间复杂度为O(1),Pythonic版本的空间复杂度为O(n)。

项目地址

后续实现的一些算法我都会统一放到GitHub,欢迎小伙伴们一起交流、学习,一起进步!下面是我的GitHub网址。
Github Data_Structure_and_Algorithm

后记:
我从本硕药学零基础转行计算机,自学路上,走过很多弯路,也庆幸自己喜欢记笔记,把知识点进行总结,帮助自己成功实现转行。
2020下半年进入职场,深感自己的不足,所以2021年给自己定了个计划,每日学一技,日积月累,厚积薄发。
如果你想和我一起交流学习,欢迎大家关注我的微信公众号每日学一技,扫描下方二维码或者搜索每日学一技关注。
这个公众号主要是分享和记录自己每日的技术学习,不定期整理子类分享,主要涉及 C – > Python – > Java,计算机基础知识,机器学习,职场技能等,简单说就是一句话,成长的见证!
每日学一技

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值