简体   繁体   English

快速排序:非就地实施工作。 就地实现超出了最大递归深度。 为什么?

[英]Quicksort: Non-in-place implementation works. In-place implementation exceeds maximum recursion depth. Why?

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)

I deliberately chose the first element as the pivot instead of randomizing to ensure that both implementations behave the same way. 我特意选择第一个元素作为枢轴,而不是随机化以确保两个实现的行为相同。

Both implementations are implemented recursively. 两种实现都是递归实现的。 In the call stack, it seems like quicksort_inplace should take O(lg n) space while quicksort_stable should take O(n) space since it creates a new list every time it recurses. 在调用堆栈中,似乎quicksort_inplace应该占用O(lg n)空间,而quicksort_stable应该占用O(n)空间,因为它每次递归时都会创建一个新列表。

Yet, quicksort_inplace is the one that causes "maximum recursion depth exceeded" while quicksort_stable works fine. 但是,quicksort_inplace是导致“超过最大递归深度”的一种,而quicksort_stable可以正常工作。

Why is this so? 为什么会这样呢?

I believe the reason for this behavior is that your list contains lots of repetitions (every element appears ~1000 times), and you "cheated" implementing the stable version by gathering all elements equal to pivot at once and not getting back to them (which is of course great!). 我相信这种行为的原因是您的列表包含很多重复(每个元素出现〜1000次),并且您“欺骗”了实现稳定版本,方法是立即收集所有等于枢轴的元素,而不是返回它们(当然很棒!)。

So to actually compare these two procedures it should look like this: 因此,要实际比较这两个过程,它应如下所示:

    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])    

Plus, in order to have the destructive (inplace) version of the above you should change a condition on your second while to greater-than (so that on right of right_idx there are elements no less than pivot ), ie 此外,为了具有破坏性(就地)版本以上,你应该改变你的第二个条件,而以大于号 (以便在right_idx的右侧有元素不超过支点以下),即

        while right_idx >= left_idx and l[right_idx] > l[start_idx]:

If you do this you'll find that both procedures cause stack overflow on arrays with 10000 elements from range(0,9) (note also that with range(0,99) this is not the case because they require less "cuts"). 如果执行此操作,您会发现这两个过程都会导致在范围为(0,9)的 10000个元素的数组上发生堆栈溢出(还请注意,对于范围为(0,99)的情况并非如此,因为它们需要较少的“剪切”) 。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM