数据结构:Python实现快速排序(2)

本文详细介绍了快速排序算法,它是一种交换排序,基本思想是分割数据并递归排序。分析了其稳定性、时间和空间复杂度,指出数据随机分布时性能好,接近有序时性能差。还介绍了用插入排序优化快排的方法,最后模拟面试展示常见问答。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

如有侵权,留言立删。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

机器不学习我学习

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值