1.什么是快速排序:
快速排序是一种交换排序。
快速排序由C. A. R. Hoare在1962年提出。
它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分:分割点左边都是比它小的数,右边都是比它大的数。
然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
图文描述如下:
输入:2,4,5,1,3
第一次排序(经过一趟快速排序)得到新的数组1,2,5,4,3
在新的数组中,以2为分割点,左边的都是比2小的数,右边的都是比2大的数。
2在数组中找到了合适的位置,不需要移动了。
2左边的元素只有一个元素1,已经有序,位置也确定了,无需移动了。(这种情况时,left指针和right指针显然是重合的,因此在代码中,我们可以通过设置判定条件left必须小于right,如果不满足,则不用排序了)
2右边的数组5,4,3,重复上面的步骤(递归实现),进行排序。
注:一开始基准的选取可以时数组中的任意数!
python3代码实现:
# -*- coding:utf-8 -*-
def quickSort(input_list, left, right):
'''
函数说明:快速排序(升序)
Parameters:
input_list - 待排序列表
Returns:
无
'''
def division(input_list, left, right):
'''
函数说明:根据left和right进行一次扫描,重新找到基准数
Parameters:
input_list - 待排序列表
left - 左指针位置
right - 右指针位置
Returns:
left - 新的基准数位置
'''
base = input_list[left]
while left < right:
while left < right and input_list[right] >= base:
right -= 1
input_list[left] = input_list[right]
while left < right and input_list[left] <= base:
left += 1
input_list[right] = input_list[left]
input_list[left] = base
return left
if left < right:
base_index = division(input_list, left, right)
quickSort(input_list, left, base_index - 1)
quickSort(input_list, base_index + 1, right)
if __name__ == '__main__':
input_list = [2, 4, 5, 1, 3]
print('排序前:', input_list)
quickSort(input_list, 0, len(input_list) - 1)
print('排序后:', input_list)
上面的如果不理解,请看这个:
def quickSort(input_list):
'''
函数说明:快速排序(升序)
'''
input_len = len(input_list) # 计算输入列表的长度
if input_len < 2: # input_list 为0,1无需排序
return input_list
# 选取基准,随便选哪个都可以,选中间的便于理解
mid = input_list[input_len // 2] # //:整除,python3中取整数部分,5//2==2,5//3==1
# 定义基准值左右两个数列
left,right = [], []
# 从原始数组中移除基准值
input_list.remove(mid)
for item in input_list:
# 大于基准值的放右边
if item >= mid:
right.append(item)
else: # 小于基准值的放左边
left.append(item)
# 使用迭代进行比较
return quickSort(left) + [mid] + quickSort(right)
input_list = [2,4,5,1,3]
print('排序前:',input_list)
sorted_list = quickSort(input_list)
print('排序后:',sorted_list)
实验结果:
2.快速排序算法分析
排序方法:快速排序
排序类别:交换排序(比较排序)
稳定性:不稳定排序
复杂性:较复杂
时间复杂度:
当待排序的数据有序时,以第一个关键字为基准分为2个子序列,前一个子序列为空,此时执行效率最差。(所以我们前面说不一定非要选第一个关键字为基准)
而当数据随机分布时,以第一个关键字为基准分为两个元素个数接近相等的子序列,此时执行效率最好。
因此,数据随机分布时,快速排序性能越好;
数据越接近有序,快速排序性能越差。
最坏情况:O(N^2)
最好情况:O(NlogN)【默认以2为底】
平均情况:O(NlogN)
空间复杂度:
快速排序在每次分割的过程中,需要1个空间存储基准值。
而快速排序大概需要NlogN次的分割处理,所以空间复杂度为NlogN
3.算法优化:
快速排序有一个缺点就是对于小规模的数据集性能不是很好。可能有人认为可以忽略这个缺点不计,因为大多数排序都只要考虑大规模的适应性就行了。但是快速排序算法使用了分治技术,最终来说大的数据集都要分为小的数据集来进行处理,所以快排分解到最后几层性能不是很好,所以我们就可以使用扬长避短的策略去优化快排:
1,首先使用快排对数据集进行排序,此时的数据集已经达到了基本有序的状态
2,然后当分区的规模达到一定小时,便停止快速排序算法,而是改用插入排序,【因为我们之前讲过插入排序在对基本有序的数据集排序有着接近线性的复杂度,】(后续补充)性能比较好。
这一改进被证明比持续使用快速排序算法要有效的多。
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]])
(上面的一行代码最好不要写啦,可读性差,用上面def定义的函数)
from 猪哥66
快排是面试与考试中最高频的一种排序算法(没有之一),请大家务必理解与掌握,欢迎大家在评论区留言,同时也希望大家转发分享让更多的人爱上python这门语言。
参与与引用:
https://www.cnblogs.com/pig66/p/10618035.html
https://www.cnblogs.com/jingmoxukong/p/4302891.html
https://cuijiahua.com/blog/2017/12/algorithm_4.html
如有侵权,留言立删。