【问题标题】:RecursionError in sorting algorithm when using Numpy array instead of list使用 Numpy 数组而不是列表时排序算法中的 RecursionError
【发布时间】:2018-10-02 20:04:59
【问题描述】:

这是我的情况:我创建了一个包含 100,000 个元素的 numpy 数组,将数组打乱,然后执行以下三件事之一:

1) 使用归并排序对数组进行排序,再次打乱数组,然后尝试使用快速排序进行排序,其中出现“RecursionError: maximum recursion depth exceeded in comparison”

2) 使用快速排序对数组进行排序,效果非常好。

3) 立即将数组转换为列表并执行第 1 步,这不会引发任何错误。

为什么只有在合并排序后运行快速排序后才会出现递归错误?

为什么我在使用列表而不是 Numpy 数组时没有收到此错误?

非常感谢您的帮助。

这里是完整的代码:

import random
import numpy as np

def quick_sort(ARRAY):
    """Pure implementation of quick sort algorithm in Python
    :param collection: some mutable ordered collection with heterogeneous
    comparable items inside
    :return: the same collection ordered by ascending
    Examples:
    >>> quick_sort([0, 5, 3, 2, 2])
    [0, 2, 2, 3, 5]
    >>> quick_sort([])
    []
    >>> quick_sort([-2, -5, -45])
    [-45, -5, -2]
    """
    ARRAY_LENGTH = len(ARRAY)
    if( ARRAY_LENGTH <= 1):
        return ARRAY
    else:
        PIVOT = ARRAY[0]
        GREATER = [ element for element in ARRAY[1:] if element > PIVOT ]
        LESSER = [ element for element in ARRAY[1:] if element <= PIVOT ]
        return quick_sort(LESSER) + [PIVOT] + quick_sort(GREATER)

def merge_sort(collection):
    """Pure implementation of the merge sort algorithm in Python
    :param collection: some mutable ordered collection with heterogeneous
    comparable items inside
    :return: the same collection ordered by ascending
    Examples:
    >>> merge_sort([0, 5, 3, 2, 2])
    [0, 2, 2, 3, 5]
    >>> merge_sort([])
    []
    >>> merge_sort([-2, -5, -45])
    [-45, -5, -2]
    """
    length = len(collection)
    if length > 1:
        midpoint = length // 2
        left_half = merge_sort(collection[:midpoint])
        right_half = merge_sort(collection[midpoint:])
        i = 0
        j = 0
        k = 0
        left_length = len(left_half)
        right_length = len(right_half)
        while i < left_length and j < right_length:
            if left_half[i] < right_half[j]:
                collection[k] = left_half[i]
                i += 1
            else:
                collection[k] = right_half[j]
                j += 1
            k += 1

        while i < left_length:
            collection[k] = left_half[i]
            i += 1
            k += 1

        while j < right_length:
            collection[k] = right_half[j]
            j += 1
            k += 1

    return collection

def is_sorted(a):
    for n in range(len(a) - 1):
        if a[n] > a[n + 1]:
            return 'not sorted'
    return 'sorted'

# Initialize
list_len = 100000                           # Define list len
print("Set list len to %s" % list_len)
data = np.arange(0, list_len, 1)            # Create array of numbers
# Alternatively: data = list(np.arange(0, list_len, 1))  <-- This WILL NOT cause an error
print("Created array")

# Shuffle
print("Shuffling array")
random.shuffle(data)                        # Shuffle array
print("List: %s" % is_sorted(data))         # Verify that list is not sorted

# Sort (merge sort)
print("Sorting array with merge sort")
merge_sort(data)                            # Sort with merge sort      
print("List: %s" % is_sorted(data))         # Verify that list is sorted

# Shuffle
print("Shuffling array")
random.shuffle(data)                        # Reshuffle list
print("List: %s" % is_sorted(data))         # Verify that list is not sorted

# Sort (quick sort)
print("Sorting array with quick sort")
print(quick_sort(data))                     # Sort with quick sort
print("List: %s" % is_sorted(data))         # Verify that list is sorted

以及完整的追溯:

Traceback (most recent call last):
File "Untitled 3.py", line 99, in <module>
    print(quick_sort(data))                     # Sort with quick sort
  File "Untitled 3.py", line 24, in quick_sort
    return quick_sort(LESSER) + [PIVOT] + quick_sort(GREATER)
  File "Untitled 3.py", line 24, in quick_sort
    return quick_sort(LESSER) + [PIVOT] + quick_sort(GREATER)
  File "Untitled 3.py", line 24, in quick_sort
    return quick_sort(LESSER) + [PIVOT] + quick_sort(GREATER)
  [Previous line repeated 993 more times]
  File "Untitled 3.py", line 22, in quick_sort
    GREATER = [ element for element in ARRAY[1:] if element > PIVOT ]
  File "Untitled 3.py", line 22, in <listcomp>
    GREATER = [ element for element in ARRAY[1:] if element > PIVOT ]
RecursionError: maximum recursion depth exceeded in comparison

当快速排序尝试对列表进行排序时,显然会发生错误。注意:我知道使用列表会更快,而且我知道我可以提高递归限制。我知道这可能是由于通过快速排序已经排序的列表引起的,但我的代码证明这不是正在发生的事情。此外,正如我之前所说,快速排序本身就可以正常工作,所以这不是由无限递归循环引起的。我出于好奇而问这个问题,以更好地了解它发生的原因。

【问题讨论】:

  • 上一个问题提到的是:stackoverflow.com/questions/49934080/…。您添加了足够的信息来覆盖先前的保留并不明显。是否有足够的信息来重现这种情况?如果有,那么我可以开始添加诊断打印和测试,以更好地确定正在发生的事情。
  • @hpaulj 我发布了这个问题,因为它回答了我上一个问题留下的所有投诉。当您询问是否有足够的信息来重现这种情况时,我不确定您在问什么。我已经发布了所有导致错误的代码,并且我假设如果您尝试在您的机器上运行代码,它会产生相同的结果。我还应该补充什么?
  • 好的,复制粘贴确实达到了限制。
  • 看来您需要测试合并后的data 是否与原始arange 数据匹配,而不仅仅是已排序。
  • 是的@hpaulj,你是对的。我希望我曾想过这样做。

标签: python arrays sorting numpy recursion


【解决方案1】:

错误在于merge_sort

numpy 数组和列表的一个重要区别是前者在切片时返回一个视图,而后者返回一个副本。

因此collectionleft_halfright_half 在处理数组时都引用相同的数据,而在列表情况下left_halfright_half 将是切片副本。

您可以通过强制复制或写入新分配的输出来解决此问题。

最终由于这个错误,一些元素将被覆盖,而另一些元素会多次出现。事实上,当我进行测试时,有很多零。

这会触发quick_sort 中的最坏情况行为:在相等元素的块中,递归将一次剃掉一个,这就是它达到递归限制的原因。

我不知道教科书解决了什么问题,但您可以在第三组中收集相同的元素。

【讨论】:

  • 所以这是我们在上一个问题中提出的问题的组合——数组使用view,最坏的情况是quick-sort。只有view 错误出现在merge-sort 中。
  • 非常感谢!这正是我一直在寻找的。这很有意义。
  • @hpaulj 是的,看起来像。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-17
  • 2019-09-12
  • 2016-07-29
  • 2012-10-12
  • 2021-10-24
相关资源
最近更新 更多