Python Max递归深度

时间:2014-12-21 09:26:45

标签: python recursion stack-trace quicksort

我在Python中实现了一些排序算法,并遇到了一个与超出最大递归深度相关的奇怪错误。在一个模块中,我实现了插入,快速和快速排序。然后我在一个单独的模块中运行一些单元测试。大值的快速排序使我的递归深度超出错误。以下是我在' 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)

我可以按照以下方式在此模块中运行测试:

 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

在我的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)

令我困惑的是,只有在运行unittest模块时才会抛出错误。这里我尝试排序5000个整数时出错。但是当我在另一个模块中运行单个快速排序测试时,我可以排除超过20000个整数而不会抛出错误。为什么会这样?


感谢大家的快速回复。我认为每个人都是正确的指出我选择枢轴的粗制方式是在已经排序的列表中产生问题。我会适当地修改它。

2 个答案:

答案 0 :(得分:2)

当列表已经排序时,您的递归无法终止。

你在单元测试中看到它失败的原因是,正如Rawing指出的那样,你的所有方法都会修改列表:所以test_list在调用InsertionSort之后已经排序了。

您应该在单独的单元测试方法中测试每个分拣机,每次都重新创建测试数据。

答案 1 :(得分:2)

您的快速排序算法在排序排序列表方面非常糟糕。您的pivot_val是第一个数字,因此排序列表分为一个数字,其余数字。 对于随机列表,所需的递归类似于log_2 N,这意味着对于20000个元素,深度大约为15.在排序的情况下,5000个元素的递归深度为5000.