目录
视频参考链接:https://www.bilibili.com/video/BV1mp4y1D7UP?p=17
一、代码
'''
思想:假设是对一个list进行排序
1、选取第一个元素作为p元素;
2、将p元素归位,即将小于p元素的元素放在列表左边,将大于p元素的元素放在列表右边
3、通过2实现了p元素的归位,这样就将列表分成了两个子列表,对左右两个子列表重复使用1、2步骤,实现快速排序
'''
import time
def partition1(li:list,left:int,right:int)->int:
'''这是根据路飞商城的思路来的
将p元素归位的函数:取第一个元素为p元素,移动right,若right指针的值大于P,
则right继续往左移动,否则停止移动,将值赋值给left所在的位置;然后再移动left,
若left指针的值小于P,则left继续往右移动,否则停止移动,将值赋值给right所在的位置;
如此交替移动,直到left=right时,停止,并将P值赋值给left(right)
:param li: 需要归位的列表
:param left: 列表左指针索引,初始值为0
:param right: 列表右指针索引,初始值为len(li)-1
:return: 返回p归位的索引
'''
#得到要归位的元素(第一个元素)
p = li[left]
#当列表有两个元素时,才进行排序
while left < right:# 保证有两个元素
#这里我们从列表的右边开始进行元素的比较
while left < right and p <= li[right]: # 至少两个元素并且p元素值小于等于right指针指向的值时,右指针左移
right -= 1 # right 左移一步
li[left] = li[right] # 不满足上述循环条件时,停止移动right,并且将right上的值赋值给left
#右指针停止移动后,开始进行左指针的移动
while left < right and p >= li[left]:
left += 1
li[right] = li[left]
#当left = right时,说明已经归位了,将p赋值给归位位置
li[left] = p
return left
def quickSorted1(li,left,right):
'''
对列表进行快排
:param li: 需要排序的列表
:param left: 左索引
:param right: 右索引
:return: 返回排好序的列表
'''
if left < right:
mid = partition1(li, left, right) # 首先得到第一个归位索引
# 对左边列表进行排序
quickSorted1(li,left,mid-1)
# 对右边列表进行排序
quickSorted1(li,mid + 1,right)
#-----------------------------------------------------------------------
def partition2(li,left,right):
'''
这个的主要思路是自己的思路
主要思路就是左右交替进行比较,然后将没有元素的位置赋值为None,如当p>右指针的值时,先将right的值赋值给left,
再将right值赋值为None,
:param li:
:param left:
:param right:
:return:
'''
p = li[left]
li[left] = None
while left < right:
if li[left] == None: # 若检测到左指针为空时
if p > li[right]: # 若p元素大于right指向的值时
li[left] = li[right] # 将right值赋值给left
li[right] = None # 此时right为空
print(li,"right")
else:
right -= 1 # 若p元素小于right值,则right左移
else:
if p < li[left]: # 若p元素小于left指向的值时
li[right] = li[left] # 将left值赋值给right
li[left] = None # 此时left为空
print(li, "left")
else:
left += 1 # 若p元素大于left值,则left右移
li[left] = p
return left
def quickSorted2(li,left,right):
'''
对列表进行快排
:param li: 需要排序的列表
:param left: 左索引
:param right: 右索引
:return: 返回排好序的列表
'''
if left < right:
mid = partition2(li, left, right) # 首先得到第一个归位索引
# 对左边列表进行排序
quickSorted2(li,left,mid-1)
# 对右边列表进行排序
quickSorted2(li,mid + 1,right)
li = [5,7,4,6,3,1,2,9,8]
startTime1 = time.time()
quickSorted1(li,0,len(li)-1)
endTime1 = time.time()
print(li,"method1")
print("method1用时:%9f"%(endTime1-startTime1))
#-----------------------------------------------------
startTime2 = time.time()
quickSorted2(li,0,len(li)-1)
endTime2 = time.time()
print(li,"method2")
print("method2用时:%9f"%(endTime2-startTime2))
二、复杂度:O(nlog(n))
当需要排序的元素个数少的时候,二者的运算速度没有什么区别,但是当数字为10000的时候,就会发生比较大的差别
第一种方法:0.04897332191467285
第二种方法:直接就报递归栈溢出的错误了。。。“进程已结束,退出代码-1073741571 (0xC00000FD)”
三、快速排序的劣势
1、对于Python会有递归最大深度的限制
2、在对一组倒序的列表进行正序时,其复杂度接近于O(n^2)
解决方法:
a、每一次随机从列表中抽取一个元素作为p元素;
b、在进行排序前,先打乱列表再进行排序,这其实是很奇妙的,通过打乱顺序来提高效率,第一次听说,但是它就是达到了这种效果,amazing~