上期文章排序算法——(2)Python实现十大常用排序算法为大家介绍了十大常用排序算法的前五种(冒泡、选择、插入、希尔、归并),因为快速排序的重要性,所以今天将单独为大家介绍一下快速排序!

一、算法介绍

排序算法(Sorting algorithm)是计算机科学最古老、最基本的课题之一。要想成为合格的程序员,就必须理解和掌握各种排序算法。其中"快速排序"(Quicksort)使用得最广泛,速度也较快。它是图灵奖得主C. A. R. Hoare(托尼·霍尔)于1960时提出来的。

二、算法原理

快排的实现方式多种多样,猪哥给大家写一种容易理解的:分治+迭代,只需要三步:

  1. 在数列之中,选择一个元素作为"基准"(pivot),或者叫比较值。
  2. 数列中所有元素都和这个基准值进行比较,如果比基准值小就移到基准值的左边,如果比基准值大就移到基准值的右边
  3. 以基准值左右两边的子列作为新数列,不断重复第一步和第二步,直到所有子集只剩下一个元素为止。

举个例子,假设我现在有一个数列需要使用快排来排序:{3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48},我们来看看使用快排的详细步骤:

  1. 选取中间的26作为基准值(基准值可以随便选)
  2. 数列从第一个元素3开始和基准值26进行比较,小于基准值,那么将它放入左边的分区中,第二个元素44比基准值26大,把它放入右边的分区中,依次类推就得到下图中的第二列。
  3. 然后依次对左右两个分区进行再分区,得到下图中的第三列,依次往下,直到最后只有一个元素
  4. 分解完成再一层一层返回,返回规则是:左边分区+基准值+右边分区

三、代码实现

quick_sort = lambda array: array if len(array) <= 1 else quick_sort([item for item in array[1:] if item <= array[0]]) + [array[0]] + quick_sort([item for item in array[1:] if item > array[0]])

是不是很简洁很秀,如果再有面试官让你手写一个快排,你就把这行写上去吧,面试官见了都要喊你秀儿,哈哈。

在你感叹python吊炸天的同时,你因该考虑到代码的可读性问题,lambda函数设计是为了代码的简洁性,但是滥用的话会导致可读性变得极差,而且现在pep8代码规范中也不建议使用lambda函数了,建议使用关键字def去定义一个函数,所以下面猪哥给大家写一段符合pythonic风格的快排代码

def quick_sort(arr):
    """快速排序"""
    if len(arr) < 2:
        return arr
    # 选取基准,随便选哪个都可以,选中间的便于理解
    mid = arr[len(arr) // 2]
    # 定义基准值左右两个数列
    left, right = [], []
    # 从原始数组中移除基准值
    arr.remove(mid)
    for item in arr:
        # 大于基准值放右边
        if item >= mid:
            right.append(item)
        else:
            # 小于基准值放左边
            left.append(item)
    # 使用迭代进行比较
    return quick_sort(left) + [mid] + quick_sort(right)

四、算法分析

  1. 稳定性:快排是一种不稳定排序,比如基准值的前后都存在与基准值相同的元素,那么相同值就会被放在一边,这样就打乱了之前的相对顺序
  2. 比较性:因为排序时元素之间需要比较,所以是比较排序
  3. 时间复杂度:快排的时间复杂度为O(nlogn)
  4. 空间复杂度:排序时需要另外申请空间,并且随着数列规模增大而增大,其复杂度为:O(nlogn)
  5. 归并排序与快排 :归并排序与快排两种排序思想都是分而治之,但是它们分解和合并的策略不一样:归并是从中间直接将数列分成两个,而快排是比较后将小的放左边大的放右边,所以在合并的时候归并排序还是需要将两个数列重新再次排序,而快排则是直接合并不再需要排序,所以快排比归并排序更高效一些,可以从示意图中比较二者之间的区别。

五、快排优化

快速排序有一个缺点就是对于小规模的数据集性能不是很好。可能有人认为可以忽略这个缺点不计,因为大多数排序都只要考虑大规模的适应性就行了。但是快速排序算法使用了分治技术,最终来说大的数据集都要分为小的数据集来进行处理,所以快排分解到最后几层性能不是很好,所以我们就可以使用扬长避短的策略去优化快排:

  1. 先使用快排对数据集进行排序,此时的数据集已经达到了基本有序的状态
  2. 然后当分区的规模达到一定小时,便停止快速排序算法,而是改用插入排序,因为我们之前讲过插入排序在对基本有序的数据集排序有着接近线性的复杂度,性能比较好。

这一改进被证明比持续使用快速排序算法要有效的多。

六、模拟面试

  • 面试官:你了解快排吗?
  • 你:略知一二
  • 面试官:那你讲讲快排的算法思想吧
  • 你:快排基本思想是:从数据集中选取一个基准,然后让数据集的每个元素和基准值比较,小于基准值的元素放入左边分区大于基准值的元素放入右边分区,最后以左右两边分区为新的数据集进行递归分区,直到只剩一个元素。
  • 面试官:快排有什么优点,有什么缺点?
  • 你:分治思想的排序在处理大数据集量时效果比较好,小数据集性能差些。
  • 面试官:那该如何优化?
  • 你:对大规模数据集进行快排,当分区的规模达到一定小时改用插入排序,插入排序在小数据规模时排序性能较好。
  • 面试官:那你能手写一个快排吗?
  • 你:
quick_sort = lambda array: array if len(array) <= 1 else quick_sort([item for item in array[1:] if item <= array[0]]) + [array[0]] + quick_sort([item for item in array[1:] if item > array[0]])

  

七、总结

快排是面试与考试中最高频的一种排序算法(没有之一),请大家务必理解与掌握,欢迎大家在评论区留言,同时也希望大家转发分享让更多的人爱上python这门语言。

Python一行代码实现快速排序的更多相关文章

  1. Python一行代码

    1:Python一行代码画出爱心 print]+(y*-)**-(x**(y*<= ,)]),-,-)]) 2:终端路径切换到某文件夹下,键入: python -m SimpleHTTPServ ...

  2. python 三行代码实现快速排序

    python 三行代码实现快速排序 最近在看 python cookbook , 里面的例子很精彩,这里就帮过来,做个备忘录 主要利用了行数的递归调用和Python的切片特性,解释一下每行代码的含义: ...

  3. 【python】10分钟教你用python一行代码搞点大新闻

    准备 相信各位对python的语言简洁已经深有领会了.那么,今天就带大家一探究竟.看看一行python代码究竟能干些什么大新闻.赶紧抄起手中的家伙,跟我来试试吧. 首先你得先在命令行进入python. ...

  4. Python一行代码搞定的事情

    python -m SimpleHTTPServer 8000 http://127.0.0.1:8000/ 有了这一行代码分享本地盘内容就不需要FTP了. pydoc:Python文档工具 pyth ...

  5. python一行代码就能搞定的事情!

    打印9*9乘法表: >>> print( '\n'.join([' '.join(['%s*%s=%-2s' % (y,x,x*y) for y in range(1,x+1)]) ...

  6. Python 一行代码

    Python语法十分便捷,通过几个简单例子了解其趣味 1.Fizz.Buzz问题为: 打印数字1到100, 3的倍数打印"Fizz", 5的倍数打印"Buzz" ...

  7. Python一行代码处理地理围栏

    最近在工作中遇到了这个一个需求,用户设定地理围栏,后台获取到实时位置信息后通过与围栏比较,判断是否越界等. 这个过程需要用到数据协议为GEOjson,通过查阅资料后,发现python的shapely库 ...

  8. python一行代码开启http

    python -m SimpleHTTPServer 8000 & 监听8000端口 浏览器用127.0.0.1:8000访问 如果出现no module named SimpleHTTPSe ...

  9. Python 一行代码实现并行

    需求 给定一个list   针对list 中每个元素执行一定的操作(这个操作很费时间,例如爬数据的时候调用某个网站的接口),返回操作后的list 例如 给定 1-10个数,在每个数字后面加个字母a 方 ...

随机推荐

  1. API管理平台XXL-API

    <API管理平台XXL-API> 一.简介 1.1 概述 XXL-API是一个简洁易用API管理平台,提供API的"管理"."文档"."M ...

  2. C#读取shp文件并获取图形保存到sde要素类中(不使用ESRI的类库,纯c#实现)

    说明:首先要将sde要素类发布成对应的要素服务,通过对要素服务的操作,实现数据在sde要素类中的增删 //向服务器发出请求 public string getPostData(string postS ...

  3. Ubuntu16+pinpoint环境搭建

    最近研究了pinpoint,稍后放上环境搭建教程,建议想学习搭建的同学记得参考pinpointGitHub

  4. RNN(Recurrent Neural Network)的几个难点

    1. vanish of gradient RNN的error相对于某个时间点t的梯度为: \(\frac{\partial E_t}{\partial W}=\sum_{k=1}^{t}\frac{ ...

  5. Ubuntu 16.04 安装 Docker

    在Ubuntu上安装Docker, 非常简单, 我测试过 16.04, 17.04, 以及最新版 18.04,都是可以成功安装,并使用的. 第一步:  启动root账号 第二步:  配置网络,能上网 ...

  6. 言简意赅的TIME_WAIT

    为什么要有TIME_WAIT? 主动关闭端发送完ACK后等2MSL(最长分节生命期),防止对端没有收到ACK这种情况,重发. 官方点,再官方点...... (1) 可靠地实现TCP全双工连接的终止: ...

  7. synchronized与Lock的区别

    两者的区别分类对比: 类别 synchronized Lock 存在层次 Java的关键字,在jvm层面上 是一个类 锁的释放 1.以获取锁的线程执行完同步代码,释放锁 2.线程执行发生异常,jvm会 ...

  8. 第八章——降维(Dimensionality Reduction)

    机器学习问题可能包含成百上千的特征.特征数量过多,不仅使得训练很耗时,而且难以找到解决方案.这一问题被称为维数灾难(curse of dimensionality).为简化问题,加速训练,就需要降维了 ...

  9. WARN: Establishing SSL connection without server's identity verification is not recommended

    0.要想用Java连接mysql数据库,首先装好JDK,配置好环境变量,将jdk*.*.*\lib放入classpath,将jdk*.*.*\bin放入path中(*.*.*表示版本号):其次安装好m ...

  10. django从0到1搭建网站

    曾经有人说我前端很水,那么在这一系列文章中我打算把前后端融合在一起来做一次网站的全面重构,希望可以把刚刚入行的同学带上正途   请尊重原创,转载请注明来源网站www.shareditor.com以及原 ...