【发布时间】:2016-11-05 21:42:33
【问题描述】:
def quicksort_stable(l):
if not l:
return l
else:
pivot = l[0]
return quicksort_stable([x for x in l if x < pivot]) \
+ [x for x in l if x == pivot] \
+ quicksort_stable([x for x in l if x > pivot])
def quicksort_inplace(l):
def partition(start_idx, end_idx):
left_idx = start_idx + 1
right_idx = end_idx
while True:
while left_idx <= right_idx and l[left_idx] <= l[start_idx]:
left_idx += 1
while right_idx >= left_idx and l[right_idx] >= l[start_idx]:
right_idx -= 1
if right_idx < left_idx:
break
else:
l[left_idx], l[right_idx] = l[right_idx], l[left_idx]
l[start_idx], l[right_idx] = l[right_idx], l[start_idx]
return right_idx
def qs(start_idx, end_idx):
if start_idx < end_idx:
split_idx = partition(start_idx, end_idx)
qs(start_idx, split_idx - 1)
qs(split_idx + 1, end_idx)
qs(0, len(l) - 1)
return l
if __name__ == '__main__':
import random
l1 = [random.randint(0, 9) for x in range(10000)]
l2 = [x for x in l1]
l1 = quicksort_stable(l1)
quicksort_inplace(l2)
我故意选择第一个元素作为枢轴而不是随机化,以确保两个实现的行为方式相同。
这两种实现都是递归实现的。在调用堆栈中,似乎 quicksort_inplace 应该占用 O(lg n) 空间,而 quicksort_stable 应该占用 O(n) 空间,因为它每次递归都会创建一个新列表。
然而,quicksort_inplace 是导致“超出最大递归深度”的原因,而 quicksort_stable 工作正常。
为什么会这样?
【问题讨论】:
-
尝试在
qs中打印start_idx和end_idx的值,这应该会给你一个线索。 -
呵呵,是不是因为小范围的数字导致 quicksort_inplace 每次递归时都会在部分排序的列表上递归,而部分排序的列表对快速排序算法不利? quicksort_stable 通过收集所有等于枢轴的元素来解决这个问题,并且不会递归。
标签: python recursion stack-overflow quicksort