快速排序是对“冒泡排序”的优化算法,都属于交换排序类。

描述:它通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据要小,然后再按此方法对这两部分数据分别进行快速排序,整个过程递归进行,以此使得整个数据变成有序序列。

值得注意:目前C++,java,PHP,JS等语言的排序源码中引用排序算法就是快速排序的改进算法实现的。

性能方面:时间性能取决于快速排序递归的深度。

\ 时间复杂度 空间复杂度
最坏情况 O(n^2) O(n)
最好情况 O(nlogn) O(logn)
平均情况 O(nlogn) O(logn)

由于关键字的比较和交换是跳跃的,所以是一种不稳定的排序。

实现代码示例:

# -*- coding:utf-8 -*-
__author__ = 'webber' def quick_sort(lst):
Qsort(lst, 0, len(lst)-1) def Qsort(lst, low, high):
if low >= high:
return # 分段无记录或只有一个记录
else:
pivot = Partition(lst, low, high) # 将lst一分为二,得出枢轴值pivot Qsort(lst, low, pivot-1) # 对低子表递归排序
Qsort(lst, pivot+1, high) # 对高子表递归排序 """
交换顺序表lst中子表的记录,使枢轴记录到位,并返回其所在位置
此时在它之前(后)的记录均不大(小)于它
"""
def Partition(lst, low, high):
pivotkey = lst[low] #用子表的第一个记录做枢轴记录
while low < high: #从表的两端交替想中间扫描
while low < high and lst[high] >= pivotkey:
high -= 1
lst[low], lst[high] = lst[high], lst[low] # 将比枢轴记录小的记录交换到低端 while low < high and lst[low] <= pivotkey:
low += 1
lst[low], lst[high] = lst[high], lst[low] # 将比枢轴记录大的记录交换到高端
return low # 返回枢轴所在位置 if __name__ == "__main__":
lst = [3, 6, 1, 2, 82, 35, -10, 12, 55]
quick_sort(lst)
print lst

快速排序的优化

1、枢轴的选取

之前的快速排序代码示例中总是固定的选取第一个关键字作为枢轴值,即pivotkey = lst[low] ,这很不合理,第一个枢轴值应该尽量为序列的中间数。

改进:三数取中法,即取序列的左端、中间、右端三个数,经过比较取得三个数的中间值作为枢轴值。(后续有人提出对于更大的序列,可以取更多的数然后得出中间值,即九数取中法。)

实现示例:

def Partition(lst, low, high):

    middle = low + (high-low)/2
if lst[low] > lst[high]:
lst[low], lst[high] = lst[high], lst[low]
if lst[middle] > lst[high]:
lst[middle], lst[high] = lst[high], lst[middle]
if lst[middle] > lst[low]:
lst[middle],lst[low] = lst[low], lst[middle] # 优化一:优化选取枢轴(三数取中法),保证lst[low]为三个数的中间值,然后赋值给pivotkey pivotkey = lst[low] #用子表的第一个记录做枢轴记录

2、优化不必要的交换

代码示例:

def Partition(lst, low, high):
pivotkey = lst[low] #用子表的第一个记录做枢轴记录
tmp = pivotkey #将枢轴关键字暂存到tmp中
while low < high: #从表的两端交替想中间扫描
while low < high and lst[high] >= pivotkey:
high -= 1
# lst[low], lst[high] = lst[high], lst[low] # 将比枢轴记录小的记录交换到低端
lst[low] = lst[high] # 采用替换而不是交换的方式
while low < high and lst[low] <= pivotkey:
low += 1
# lst[low], lst[high] = lst[high], lst[low] # 将比枢轴记录大的记录交换到高端
lst[high] = lst[low] # 采用替换而不是交换的方式
lst[low] = tmp #将枢轴值替换回lst[low]
return low # 返回枢轴所在位置

3、优化小数组时的排序方案

由于递归对于长度较小的序列反而会拖累算法的性能,所以需要与简单排序相结合,这里用简单排序中性能相对来说较好的插入排序。

代码示例如下:需要在Qsort中加一个阈值的判别,有人认为7更合适,也有人认为50更合适,这样,无论多长的排序序列,当被递归分成小于等于7的序列时,就用插入排序实现。

MAX_LENGTH_INSERT_SORT = 7
def Qsort(lst, low, high):
if low >= high:
return # 分段无记录或只有一个记录
else:
if (high-low) > MAX_LENGTH_INSERT_SORT: #优化三:设定阈值,在阈值内则用插入排序
pivot = Partition(lst, low, high) # 将lst一分为二,得出枢轴值pivot Qsort(lst, low, pivot-1) # 对低子表递归排序
Qsort(lst, pivot+1, high) # 对高子表递归排序
else:
insert_sort(lst)

4、对递归操作的优化

在Qsort中分别对高子表和低子表进行递归排序,当待排序序列划分极端不平衡时,会增加递归的深度,严重影响性能。所以可通过对Qsort实现“尾递归”来进行优化。

代码示例如下:

def Qsort(lst, low, high):
if low >= high:
return # 分段无记录或只有一个记录
else:
if (high-low) > MAX_LENGTH_INSERT_SORT: #优化三:设定阈值,在阈值内则用插入排序
while low < high: # 优化四:对递归操作的优化
pivot = Partition(lst, low, high) # 将lst一分为二,得出枢轴值pivot Qsort(lst, low, pivot-1) # 对低子表递归排序
# Qsort(lst, pivot+1, high) # 对高子表递归排序
low = pivot + 1 # 尾递归
else:
insert_sort(lst)

这样的结果是相同的,但因采用迭代而不是递归的方法,可以缩减堆栈的深度,从而在待排序序列划分极端不平衡时大大提高了整体的性能。

关于性能测试

if __name__ == "__main__":
start = time.clock() rand_lst = []
for i in range(10000):
rand_lst.append(round(random.random()*100, 2))
quick_sort(rand_lst) end = time.clock()
print "done ", (end-start)

分别生成不同长度的随机数序列,1000、5000、10000等等,发现MAX_LENGTH_INSERT_SORT = 50时排序耗时更少,而且这里有个问题,可能是python的内部优化的更好一些,快速排序的优化一和优化二对于性能的提升帮助很大,排序10000的随机数只需要0.03秒,但是经过优化三和优化四之后,反而需要至少5秒的排序时间,这里没想通,所以觉得或许是python的优化机制不同,对于递归深度的支持更好一些。这里遗留一个问题。。。

python 快速排序详述的更多相关文章

  1. Python3基础-Python作用域详述(转载)

    转载文章 转载文章 作者:骏马金龙 出处:http://www.cnblogs.com/f-ck-need-u/p/9925021.html Python作用域详述 作用域是指变量的生效范围,例如本地 ...

  2. 三.Python数据类型详述

    Python第三节数据类型详述 一.多变量赋值 python允许多变量赋值 多变量赋相同的值a = b = c = 1 多变量赋不同的值a, b, c = 1, 2, "fuckyou&qu ...

  3. python --- 快速排序算法

    在快速排序中引入递归和分治的概念(关于递归和分治的概念会单独写一篇来进行介绍) 问的解决思路: 快速排序的基本思想本身就是分治法,通过分割,将无序序列分成两部分,其中前一部分的元素值都要小于后一部分的 ...

  4. Python作用域详述

    作用域是指变量的生效范围,例如本地变量.全局变量描述的就是不同的生效范围. python的变量作用域的规则非常简单,可以说是所有语言中最直观.最容易理解的作用域. 在开始介绍作用域之前,先抛一个问题: ...

  5. Python 快速排序 算法

    基本的快排算法,二分法 #!/usr/bin/env python # encoding: utf-8 l1=[1,4,2,6,3] def path_sort(l,start_index,end_i ...

  6. Python—快速排序算法

    # _*_ coding=utf-8 _*_ """ 快速排序: 通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比 另外一部分的所有数据都要小,然后 ...

  7. Python快速排序

    快排,取一个key值,一般取第一个即可,将小于key的放到左边,大于key的放到右边,递归实现 import random def quicksort(data, low = 0, high = No ...

  8. python 快速排序 qsort

    def qsort(arr, start, end): if start > end: return def partition(arr, start, end): pivot = arr[st ...

  9. python 快速排序 完整

    两头开始 以第一个为基准,从有往左,找第一个比基准数 大的,然后交换 从左往右,找第一个比基准数晓得,然后交换 遍历剩下的 基准数  左边的数们  以及  基准数 右边的数们 def quick_so ...

随机推荐

  1. session的作用范围(转)

    session是在服务器端建立的,浏览器访问服务器会有一个jsessionid,浏览器端通过 jsessionid定位服务器端的session,session的创建和销毁由服务器端控制.当浏览器关闭后 ...

  2. Linux Ubuntu下Dropbox图标消失

    Linux下的Dropbox是支持命令行模式的.,在terminal中输入dropbox后,如下提示: Dropbox command-line interface commands: Note: u ...

  3. MSSQL数据库导入导出大全二(SQL语句)

    Excel文件导入数据库多个Sheet if exists(select 1 from sysobjects where name=N'p_import_excel' and type='P')dro ...

  4. 【转载】WEB系统性能问题的分析定位方法

    以一个典型的WEB系统来举例,性能问题一般体现在客户端请求后的响应时间上.在性能测试过程中,即压力增大到某个程度后,响应时间指标迅速增长.但如那篇文章所说,这只能叫做一个现象,测试人员需要找到问题所在 ...

  5. redis有序集合的一个应用

    一.需求 记录用户uid和上次操作时间;并清除5分钟以前的数据.用redis的一个key实现.本打算用hash,但hash类型在过期5分钟以前的数据时颇为麻烦. 二.代码实现 class LastLo ...

  6. 正则表达式Pattern ,Matcher

    正则表达式:符合一定规则的表达式 作用:用于专门操作字符串 特点:用于一些特定的符号来表示一些代码的操作,这样就简化代码的书写 学习正则表达式就是要学习一些特殊符号的使用 好处:简化对字符串复杂的操作 ...

  7. 约瑟夫环用php实现

    百度百科的解释:约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围.从编号为k的人开始报数,数到m的那个人出列:他的下一个人又从1开始报数,数 ...

  8. 转 SQL行转列汇总

    1.PIVOT 用于将列值旋转为列名(即行转列) PIVOT 的一般语法是:PIVOT(聚合函数(列名) FOR 列名 in (列值1,…) )AS P select * from TB pivot ...

  9. Paxos 学习总结

    近期学习了分布式领域的重要算法Paxos,这里罗列下关键点当作总结.自己水平有限,难免存在谬误,恳请读者指正.本篇不包含Paxos的基本理论介绍.Paxos基础能够參考以下的学习资料章节. 1 Pax ...

  10. HTML css样式

    clear: both清除左侧和右侧浮动 status: 变量状态参数,该属性有5个常用值count 表示当前遍历集合的元素个数index 表示当前遍历到集合的第几个元素current 表示当前的集合 ...