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工作正常。
为什么会这样?
答案 0 :(得分:0)
我认为这种行为的原因是你的列表包含大量的重复(每个元素出现~1000次),你被欺骗了#34;通过立即收集所有等于pivot的元素并且不回复它们来实现 stable 版本(这当然很棒!)。
所以要真正比较这两个程序,它应该是这样的:
def quicksort_stable(l):
if not l or len(l)==1:
return l
else:
pivot = l[0]
rst = l[1:]
return quicksort_stable([x for x in rst if x < pivot]) \
+ [pivot] \
+ quicksort_stable([x for x in rst if x >= pivot])
另外,为了获得上述版本的破坏性(inplace)版本,您应该在第二个时更改条件,而大于(以便在 right_idx右侧有不少于 pivot 的元素,即
while right_idx >= left_idx and l[right_idx] > l[start_idx]:
如果你这样做,你会发现这两个程序都会导致数组上的堆栈溢出,其中包含来自范围(0,9)的10000个元素(另请注意范围(0, 99)情况并非如此,因为它们需要更少的&#34;削减&#34;)。