算法

数据结构

快速排序python实现总结

背景:数据结构与算法是IT相关的工程师一直以来的基础考察重点,很多经典书籍都是用c++或者java来实现,出于对python编码效率的喜爱,于是取search了一下python的快排实现,发现大家写的都比较个性,也所以我也总结下自己理解的python快排实现。

注:本随笔注重代码实现,如果是对快速排序无任何接触的还是先看一下相关的书籍

快速排序简介:快速排序是突破O(n^2)时间复杂度上界的排序算法,其平均情况下和最好情况是的时间复杂度都是O(nlogn),最差情况下的时间复杂度为O(n^2)(最差情况下退化为选择排序),空间复杂度为O(logn)

核心思想:

核心为 partition() 函数,该函数每调用一次,会产生两个作用:

例子:待排序数组为[3,5,1,8,2,4],调用一次该函数后数组变为[2,1,3,8,5,4]

直接作用:确定待排序数组上某个位置的值(我们称这个值为枢轴);在上例中表现为确定了待排序数组中索引为2(第3个元素)的值,元素'3'即为枢轴的值

副作用:将待排序数据分为了3个部分,即 [小于等于枢轴的待排序数组]+枢轴+[大于等于枢轴的待排序数组],副作用的贡献体现在减少了分治的次数

快速排序=对待排序数组采用分治+递归的方法调用partition()函数

partition()函数的时间复杂度为O(n),分治+递归调用的平均时间复杂度为O(logn),所以总体相乘为O(nlogn)

python代码实现

第一种实现,partition借助额外的list,所以partition函数的空间复杂度为O(n),因为涉及分治+递归调用,递归使用的隐含栈需要O(logn)的时间复杂度,所以整体空间复杂度为O(nlogn),借助额外的数据结构一般会起到两个效果:1、降低时间复杂度 或者 2、提高代码可读性(易于理解),这里并没有降低时间复杂度

defquick_sort1(lst):"""快速排序"""

defpartition(lst, left, right):#借助两个临时列表存放小于枢轴的元素和大于枢轴的元素

l_list, r_list =[], []#选取待排序列表的最左元素作为枢轴

pivot_value =lst[left]for i in lst[left+1:right+1]:if i<=pivot_value:

l_list.append(i)else:

r_list.append(i)#因为是原地排序,所以对原待排序数组的相应元素进行替换

lst[left:right+1] = l_list+[pivot_value]+r_listreturn left+len(l_list)defq_sort(lst, left, right):"""辅助函数,便于递归调用"""

if left>=right:returnpivot_key=partition(lst, left, right)

q_sort(lst, left, pivot_key-1)

q_sort(lst, pivot_key+1, right)if not lst or len(lst)==0:returnlst

q_sort(lst, 0, len(lst)-1)return lst

上述实现采用了额外的list,虽然增加了可读性,但是提高了空间复杂度,所以,可以对其优化,将partition函数的空间复杂度降为O(1)

第二种实现,不借助额外列表

defquick_sort2(lst):"""快速排序"""

defpartition(lst, left, right):#默认选择列表最左元素作为枢轴

pivot_value =lst[left]while left=pivot_value:

right-=1

#当右指针对应元素小于枢轴的值,将左右指针对应元素交换,使小于枢轴的值位于枢轴的左侧

lst[left], lst[right] =lst[right], lst[left]while left

left+=1

#当左指针对应元素大于枢轴的值,将左右指针对应元素交换,使大于枢轴的值位于枢轴的右侧

lst[left], lst[right] =lst[right], lst[left]returnleftdefq_sort(lst, left, right):if left>=right:returnpivot_key=partition(lst, left, right)

q_sort(lst, left, pivot_key-1)

q_sort(lst, pivot_key+1, right)if not lst or len(lst)==0:returnlst

q_sort(lst, 0, len(lst)-1)return lst

这里通过元素交换的方式达到了与方法1同样的效果,所以在很多资料上,快速排序和冒泡排序都被分类为'交换排序',但有一点要注意,快速排序最差的情况下,会退化为选择排序而非冒泡排序

针对第二种情况,我们还可以继续优化,省去不必要的交换,将"交换"优化为“替换”

第三种实现

defquick_sort3(lst):"""快速排序"""

defpartition(lst, left, right):#默认选择列表最左元素作为枢轴,同时也记录了left最初对应的元素值

pivot_value =lst[left]while left=pivot_value:

right-=1

#将left对应的元素替换为right(小于枢轴)对应的元素

lst[left] =lst[right]while left

left+=1

#将right对应的元素替换为left(大于枢轴)对应的元素

lst[right] =lst[left]#当left和right相等时,使用最初记录的left对应的元素值替换当前指针的元素

lst[left] =pivot_value#返回枢轴对应的索引

returnleftdefq_sort(lst, left, right):if left>=right:returnpivot_key=partition(lst, left, right)

q_sort(lst, left, pivot_key-1)

q_sort(lst, pivot_key+1, right)if not lst or len(lst)==0:returnlst

q_sort(lst, 0, len(lst)-1)return lst

第三种方案和前两种一样,都是将列表的最左元素作为枢轴,这也是导致快速排序最差情况时间复杂度为O(n^2)的原因,比如每次列表的最左元素都为最大值或者最小值,那每次对partition函数的调用只起到了直接作用(确定了列表的最左端的最小值或者最右端的最大值),而没有起到副作用(副作用的目的是减小分治次数)

所以我们可以对枢轴的选取进行优化,优化的目的是使枢轴的选取避开最大值或最小值,尽量靠近中位数,优化的思路有两种

1、随机选取

2、选取列表中left, right, (left+right)//2,三个索引位置对应元素居中的元素

由于随机数的生成在编程语言API中的实现也要耗费一定的时间复杂度,所以我们选择2

第四种实现如下

defquick_sort4(lst):"""快速排序"""

defpartition(lst, left, right):#计算中间索引

mid = (left+right)//2

#将三个元素中大小居中的元素交换至列表的最左侧

if lst[left]>lst[mid]:

lst[left], lst[mid]=lst[mid], lst[left]if lst[mid]>lst[right]:

lst[mid], lst[right]=lst[right], lst[mid]if lst[left]

lst[left], lst[mid]=lst[mid],lst[left]

pivot_value=lst[left]while left=pivot_value:

right-=1lst[left]=lst[right]while left

left+=1lst[right]=lst[left]

lst[left]=pivot_valuereturnleftdefq_sort(lst, left, right):if left>=right:returnpivot_key=partition(lst, left, right)

q_sort(lst, left, pivot_key-1)

q_sort(lst, pivot_key+1, right)if not lst or len(lst)==0:returnlst

q_sort(lst, 0, len(lst)-1)return lst

经过2~4的优化,我们已经

1)把空间复杂度由O(nlogn)降至O(n),yi

2)并尽量优化了最差情况下的时间复杂度,使其比O(n^2)要好一些

但需要提醒一下,其最佳情况下的时间复杂度依旧使O(nlogn),而一些简单排序算法,如插入排序和优化后的冒泡排序的最优时间复杂度都可以达到O(n)

快排在面对大量数据排序时表现良好,

所以可以进行优化,当待排序数据的元素数量小于某个常数值时采用插入排序,否则使用快速排序

第五种实现

defquick_sort5(lst):"""快速排序"""

defpartition(lst, left, right):#计算中间索引

mid = (left+right)//2

#将三个元素中大小居中的元素交换至列表的最左侧

if lst[left]>lst[mid]:

lst[left], lst[mid]=lst[mid], lst[left]if lst[mid]>lst[right]:

lst[mid], lst[right]=lst[right], lst[mid]if lst[left]

lst[left], lst[mid]=lst[mid],lst[left]

pivot_value=lst[left]while left=pivot_value:

right-=1lst[left]=lst[right]while left

left+=1lst[right]=lst[left]

lst[left]=pivot_valuereturnleftdefq_sort(lst, left, right):if left>=right:returnpivot_key=partition(lst, left, right)

q_sort(lst, left, pivot_key-1)

q_sort(lst, pivot_key+1, right)if not lst or len(lst)==0:returnlst#取某个常数,待排序元素数量大于该常数时使用快排,否则使用插入排序

if len(lst)>50:

q_sort(lst, 0, len(lst)-1)else:#插入排序在此不实现了,大家自行解决

insert_sort(lst)return lst

经过上述优化,我们做到了

1)空间复杂度由O(nlogn)优化至O(logn)

2)  将最差情况下的时间复杂度O(n^2)尽可能提升

3)将时间复杂度的下界提升至O(n),当然,这已经不是单纯的快排了- -!

刚开始写博客,有不对的地方还望指教~~~

内容来源于网络,如有侵权请联系客服删除

python快速排序解析_快速排序python实现总结相关推荐

  1. python xmlns 解析_使用python读取标记中包含xmlns的XML文件

    我试图从xml文件中读取一个元素来添加新元素. 我试图找到的标签包含xmlns. 它看起来像这样: 我的python代码如下所示: import xml.etree.ElementTree as xm ...

  2. python天天向上解析_用Python编程帮你验证“好好学习,天天向上”的重要性!

    首先,在这里提一下这个被反复说起无数遍的问题: 一年365天,每天进步1‰,累计进步多少呢? 一年365天,每天退步1‰,累计退步多少呢? 这个问题如果作为数学问题是很简单的,我们先以千分之一为例,保 ...

  3. python 时间序列预测_使用Python进行动手时间序列预测

    python 时间序列预测 Time series analysis is the endeavor of extracting meaningful summary and statistical ...

  4. python 概率分布模型_使用python的概率模型进行公司估值

    python 概率分布模型 Note from Towards Data Science's editors: While we allow independent authors to publis ...

  5. python 日期解析_如何在Python中解析ISO 8601格式的日期?

    python 日期解析 Python provides a datetime standard library which introduces datetime.isoformat(). As pe ...

  6. python 参数封装_扩展Python模块系列(三)----参数解析与结果封装

    在上一节中,通过一个简单的例子介绍了C语言扩展Python内建模块的整体流程,从本节开始讲开始深入讨论一些细节问题,在细节讨论中从始至终都会涉及[引用计数]的问题.首先讨论C语言封装的Python函数 ...

  7. python 网页编程_通过Python编程检索网页

    python 网页编程 The internet and the World Wide Web (WWW), is probably the most prominent source of info ...

  8. python 创意项目_针对python开发人员的10个很棒的python项目创意

    python 创意项目 The joy of coding Python should be in seeing short, concise, readable classes that expre ...

  9. python queue 调试_学Python不是盲目的,是有做过功课认真去了解的

    有多少伙伴是因为一句'人生苦短,我用Python'萌生想法学Python的!我跟大家更新过很多Python学习教程普及过多次的Python相关知识,不过大家还是还得计划一下Python学习路线!Pyt ...

最新文章

  1. 项目进展情况如何更好地管理?
  2. C++文件如何在linux下生成动态库So,以及如何使用这个动态库
  3. html模板是干嘛的,html模板有什么用
  4. linux日志分析与痕迹清理
  5. 分库分表的事务处理机制
  6. dexpress 流程图_DevExpress控件使用经验总结
  7. JDDroppableView
  8. leetcode9. 回文数
  9. 设计灵感在哪里?集设网海纳百川,智慧的聚集地
  10. Java:多线程模拟多站点售票过程
  11. 搭建局域网HTTP FTP服务
  12. 华为不可参与 IEEE 审稿但可继续提供赞助;谷歌限制 Chrome 接口惹非议;Mozilla 号召用户换火狐 | 开发者周刊...
  13. [转载] python判断是否为json_Python判断变量是否为Json格式的字符串示例
  14. 3dmax用vr渲染还是cr渲染器?
  15. itools 苹果录屏大师 java_AirPlayer电脑版(itools苹果录屏大师)下载|AirPlayer电脑免费版...
  16. 如何设置线程池参数?美团给出了一个让面试官虎躯一震的回答。
  17. Bugku之秋名山老司机
  18. 设计模式系列:搞懂装饰器模式,增加自身技能
  19. html 拓扑图 开源,GitHub - pylixm/zJTopo: 开源拓扑图工具类jTopo的扩展,jtopo是一个不错的拓扑图,基于html5 canvas,功能强大...
  20. [机器学习] SSE,MSE,RMSE,R-square指标讲解

热门文章

  1. linux修改网卡mac
  2. Apache Nutch 1.3 学习笔记十一(页面评分机制 OPIC)
  3. TikTok英国市场你不能不知道的10大数据
  4. DedeCms模板防盗的方法
  5. Java设计模式---桥接Bridge模式
  6. Scrapy框架----pipeline---------数据保存EXCEL
  7. js生成元素的事件不执行问题
  8. c++笔试题两道,求解当中一道
  9. Selenium之Android使用学习
  10. 打造自己的数据访问层(二)