简体   繁体   English

Python最大递归深度

[英]Python Max Recursion Depth

I am implementing some sorting algorithm in Python and encountered a somewhat strange bug related to max recursion depth being exceeded. 我正在Python中实现某种排序算法,遇到了一个与超出最大递归深度有关的怪异错误。 In one module, I have implemented an insertion,m erge, and quicksort. 在一个模块中,我实现了插入,合并和快速排序。 I then run some unit tests in a separate module. 然后,我在单独的模块中运行一些单元测试。 The quicksort on large values is giving me recursion depth exceeded errors. 快速排序大值给我递归深度超出错误。 Here is my implementation of the algorithm in 'Sorter.py': 这是我在“ Sorter.py”中算法的实现:

class QuickSort(Sorter):
    """Implements quicksort algorithm.
    Best case: O(n*log(n))
    Worst case: O(n^2)
    Average case: O(n*log(n))
    """
    @staticmethod
    def partition(numbers, low, high):
        pivot_index = low #crappy way to pick a pivot but it'll do
        pivot_val = numbers[pivot_index]

        #swap pivot with high
        temp = numbers[high]
        numbers[high] = pivot_val
        numbers[pivot_index] = temp

        store_index = low
        for index in range(low, high):
            if numbers[index] < pivot_val:
                #Swap 'index' with 'store_index'
                temp = numbers[store_index]
                numbers[store_index] = numbers[index]
                numbers[index] = temp

                store_index += 1

        #Swap pivot_val at high into appropriate index
        temp = numbers[store_index]
        numbers[store_index] = numbers[high] 
        numbers[high] = temp

        return store_index

    @staticmethod
    def sort_helper(numbers, low, high):
        if low < high:
            part_index = QuickSort.partition(numbers, low, high)
            QuickSort.sort_helper(numbers, low, part_index)
            QuickSort.sort_helper(numbers, part_index+1, high)
        return numbers  

    @classmethod
    def sort(cls, numbers):
        assert len(numbers) != 0, "Must provide a non-empty list"
        return QuickSort.sort_helper(numbers, 0, len(numbers)-1)

I can run tests in this module as follows for: 我可以在此模块中运行以下测试:

 if __name__ == '__main__':
    seq = random.sample(xrange(1,100000), 10000)
    print 'Original Seq: ', seq
    real = sorted(seq)
    quick = QuickSort.sort(seq)
    print "Real Sorted: ", real
    print 'Quick Sorted: ', quick

In my unittest module, I run the following as a test: 在我的unittest模块中,我运行以下作为测试:

def test_really_large(self):
    """Tests handling of a very large sequence."""
    test_list = random.sample(xrange(1,10000), 5000)
    real_sorted = sorted(test_list)
    insert_sorted = InsertionSort.sort(test_list)
    merge_sorted = MergeSort.sort(test_list)
    quick_sorted = QuickSort.sort(test_list)

    self.assertEqual(real_sorted, insert_sorted)
    self.assertEqual(real_sorted, merge_sorted)
    self.assertEqual(real_sorted, quick_sorted)

What confuses me is that an error is only thrown when I run the unittest module. 令我困惑的是,仅当我运行unittest模块时才会引发错误。 Here I get an error when I try to sort 5000 integers. 当我尝试对5000个整数进行排序时,出现错误。 However when I run a single quicksort test in the other module, I can sort beyond 20000 integers without an error being thrown. 但是,当我在另一个模块中运行单个quicksort测试时,我可以对超过20000个整数进行排序,而不会引发错误。 Why is this happening? 为什么会这样呢?


Thanks to everyone for the quick responses. 感谢大家的快速反应。 I think everyone is correct in pointing out that my shoddy way of choosing the pivot is what's creating a problem with already sorted lists. 我认为每个人都正确地指出,我选择支点的伪劣方法是造成已经排序的列表出现问题。 I will modify this appropriately. 我将对此进行适当的修改。

Your recursion fails to terminate when the list is already sorted. 对列表进行排序后,您的递归操作将无法终止。

The reason why you're seeing it fail only in the unit test is that, as Rawing pointed out, all your methods modify the list in place: so test_list is already sorted after the call to InsertionSort. 正如Rawing指出的那样,您看到它仅在单元测试中失败的原因是,所有方法都在适当的地方修改了列表:因此test_list已经在对InsertionSort的调用之后进行了排序。

You should test each sorter in a separate unit test method, recreating the test data each time. 您应该使用单独的单元测试方法测试每个分类器,每次都重新创建测试数据。

Your quicksort algorithm is very bad at sorting sorted lists. 您的quicksort算法在排序列表时非常不好。 Your pivot_val is the first number, so a sorted list is partitioned in one number and the rest. 您的pivot_val是第一个数字,因此,已排序的列表分为一个数字和其余的数字。 For random lists, the recursion needed is something like log_2 N, that means for 20000 elements the depth is about 15. In your sorted case, the recursion depth of 5000 elements is 5000. 对于随机列表,所需的递归类似于log_2 N,这意味着对于20000个元素,深度约为15。在排序的情况下,5000个元素的递归深度为5000。

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

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