2024.6.29--------------------------------------------------------------------------------------------------------------------
最近用python写了一个快排,然后上网参考大佬们都是怎么写的,发现两种写法:一种返回排好的列表,一种直接对列表进行修改。
我最开始的想法是返回排序好的列表,代码如下:
def quick_sort(n):
if len(n) < 2:
return n
pick = n[0]
left = 0
right = len(n) - 1
while left < right:
while (n[right] >= pick) and (left < right):
right -= 1
n[left] = n[right]
while (n[left] < pick) and (left < right):
left += 1
n[right] = n[left]
n[left] = pick
llist = quick_sort(n[:left+1])
rlist = quick_sort(n[right+1:])
if rlist:
llist.extend(rlist)
return llist
print(quick_sort([3,2,6,0,1,7,4,9]))
虽然进行了删减,但还是显得有点冗长。后来在菜鸟上看到另一种写法,直接对列表本身进行修改而不返回列表(python列表、字典、集合是可变对象,按引用传递http://t.csdnimg.cn/8Rjdj)。于是我打算在方法一的基础上直接修改,但是返回的结果只进行了一次排序,即 [1, 2, 0, 3, 6, 7, 4, 9]。代码如下:
def quick_sort(n):
if len(n) > 0:
pick = n[0]
left = 0
right = len(n) - 1
while left < right:
while (n[right] >= pick) and (left < right):
right -= 1
n[left] = n[right]
while (n[left] < pick) and (left < right):
left += 1
n[right] = n[left]
n[left] = pick
print(f"test: n is {n}")
quick_sort(n[:left])
quick_sort(n[right+1:])
n = [3,2,6,0,1,7,4,9]
quick_sort(n)
print(n)
后来通过print函数发现排序是正常进行的,但为什么结果只排了一次呢?对比网上写法,我发现用此方法递归传参的时候必须仍用‘n'而不能另外传个新的列表’n[x:y]'。如是简单修改一下就正常运行了。方法二最终代码如下:
def quick_sort(n,start,end): # 使用此方法递归时仍要传相同的列表n,不能传新列表
if start < end:
left = start
right = end
pick = n[left]
while left < right:
while (n[right] >= pick) and (left < right):
right -= 1
n[left] = n[right]
while (n[left] < pick) and (left < right):
left += 1
n[right] = n[left]
n[left] = pick
quick_sort(n,start,left-1)
quick_sort(n,right+1,end)
n = [3,2,6,0,1,7,4,9]
quick_sort(n,0,len(n)-1)
print(n)
2024.7.7---------------------------------------------------------------------------------------------------------------------
今天想到测一测三种写法的运行时间,代码如下:
import time
import random
random_list = [random.randint(0,10000000) for i in range(999)]
time1 = time.time()
# 方法1:
def quick_sort(n):
length = len(n)
if length < 2:
return n
pick = n[0]
left = 0
right = length - 1
while left < right:
while (n[right] >= pick) and (left < right):
right -= 1
n[left] = n[right]
while (n[left] < pick) and (left < right):
left += 1
n[right] = n[left]
n[left] = pick
llist = quick_sort(n[:left+1])
rlist = quick_sort(n[right+1:])
if rlist:
llist.extend(rlist)
return llist
a = quick_sort(random_list)
print(a)
time2 = time.time()
# 菜鸟给出的方法:
def partition(arr,low,high):
i = ( low-1 )
pivot = arr[high]
for j in range(low , high+1):
if arr[j] <= pivot:
i = i+1
arr[i],arr[j] = arr[j],arr[i]
return i
def quickSort(arr,low,high):
if low < high:
pi = partition(arr,low,high)
quickSort(arr, low, pi-1)
quickSort(arr, pi+1, high)
b = random_list
length = len(b)
quickSort(b,0,length-1)
print(b)
time3 = time.time()
# 方法2:
def quicksort(n,start,end): # 使用此方法递归时仍要传相同的列表n,不能传新列表
if start < end:
left = start
right = end
pick = n[left]
while left < right:
while (n[right] >= pick) and (left < right):
right -= 1
n[left] = n[right]
while (n[left] < pick) and (left < right):
left += 1
n[right] = n[left]
n[left] = pick
quicksort(n,start,left-1)
quicksort(n,right+1,end)
c = random_list
quicksort(c,0,len(c)-1)
print(c)
time4 = time.time()
print(f'Method 1 consume {time2 - time1}s')
print(f'Cainiao consume {time3 - time2}s')
print(f'Method 2 consume {time4 - time3}s')
结果如下:
Method 1 consume 0.003503084182739258s
Cainiao consume 0.003007173538208008s
Method 2 consume 0.02008533477783203s
三种方法结果是一样的,这里就不粘贴过来了。可以发现方法2明显比另外两种方法更慢,同时当列表长度大于等于1000时,方法2就会报错:
[Previous line repeated 995 more times]
RecursionError: maximum recursion depth exceeded
而三种方法单独运行时又不会出现这种错误,不清楚是否是因为栈溢出造成的错误,期待路过的大佬帮忙解答!
以下为单独运行三种函数,数据量为1000并注释掉print函数后的运行速度:
Method 1 consume 0.0009996891021728516s
Cainiao consume 0.0009779930114746094s
Method 2 consume 0.0009951591491699219s
三种方法速度似乎差不多,下面改用数据量为一百万时的运行速度,并增加了方法3(基于方法1将while循环改为for循环):
# 方法3:
def quicksort(n):
length = len(n)
if length < 2:
return n
pick = n[length-1]
left = 0
for i in range(length):
if n[i] <= pick:
n[left], n[i] = n[i], n[left]
left += 1
llist = quicksort(n[:left-1])
rlist = quicksort(n[left-1:])
if rlist:
llist.extend(rlist)
return llist
d = quicksort(random_list)
Method 1 consume 1.9789748191833496s
Cainiao consume 1.6710314750671387s
Method 2 consume 1.5303723812103271s
Method 3 consume 2.0696356296539307s
方法1、3较慢的速度或许是因为需要反复对列表长度进行测量而中间两种方法直接以O(1)的时间传递了所需处理的列表长度。并且我们发现while循环与for循环在时间上似乎并无明显区别。