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

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

值得注意:目前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. Jenkins 安装卡住不动的解决方案

    如果在安装jenkins时卡在getting startted的界面,如下所示 jenkins在安装插件前总是尝试连接www.google.com,来判断网络是否连通.谷歌的网站在大陆是连不上的,所以 ...

  2. 开源jabber(XMPP)架设内部即时通讯服务的解决方案

    Jabber 是著名的即时通讯服务服务器,它是一个自由开源软件,能让用户自己架即时通讯服务器,可以在Internet上应用,也可以在局域网中应用.    XMPP(可扩展消息处理现场协议)是基于可扩展 ...

  3. Sending SMS And Dialing Numbers without User Consent(Context is not needed)

    Sending SMS And Dialing Numbers without User Consent Sending SMS does not require context or user in ...

  4. 改进xutils下载管理器,使其,在随意地方进行进度更新,以及其它状态监听操作

    1.前面在做下载进度监听.尝试过,通过加入 弱引用的View进度条,到相应的集合. 等到要进行更新进度的时候.通过Key 获取相应的VIew来进行更新 进度条.效果是达到了,可是我们怎样来监听其它的状 ...

  5. Android无数据线调试方法

    平时在Android设备上调试程序.通常是将Android设备用数据线和PC机相连. 可是,在没有数据线的情况下也能够: 1.将PC机和Android设备连到同一网段. 2.获取Android设备的I ...

  6. JavaScript创建块级作用域

    1.JavaScript创建块级作用域 (1)方法一:ES6 (2)方法二:闭包 2.示例 <!DOCTYPE html> <html lang="zh"> ...

  7. excel表格快捷键

    CTRL+A   全选     CTRL+B   加粗       CTRL+C   复制      CTRL+D   下拉(复制上一个单元格的格式和内容)    CTRL+G   定位 CTRL+F ...

  8. C#开发--FTP操作方法管理

    1.整理简化了下C#的ftp操作,方便使用    1.支持创建多级目录    2.批量删除    3.整个目录上传    4.整个目录删除    5.整个目录下载 2.调用方法展示, var ftp ...

  9. c#关于int(或其他类型)的字段在对象初始化时默认初始化问题的解决方法

    问题: c#的wcf服务接口在后台通过自定义对象接收前台参数的时候,前台参数即使不传int类型的字段值,后台也会默认初始化为0,由于很多表示状态的int字段都是从0开始的,导致查询的时候有些不想参与查 ...

  10. asp.net core mvc视频A:笔记2-2.接收数据

    传参方式一:使用内置方法传递 运行结果 其他获取方法 Session对象在HttpContext中 启用Session 使用Session 运行演示 传参方式二:数据绑定 普通类型(string).自 ...