【问题标题】:Is there a Python implementation of quicksort without recursion?是否有没有递归的快速排序的 Python 实现?
【发布时间】:2021-10-02 01:10:02
【问题描述】:

我试图在不使用递归的情况下在 Python 中实现快速排序,但到目前为止我发现的所有参考实现或伪代码都使用递归。

这样做的原因是我将调整这个非递归实现以在使用 Numba 的 GPU 上运行,而我不能在那里进行递归调用。

是否有不使用递归的一维数组(例如,Numpy 数组或 Python 列表)的快速排序实现?

谢谢,

爱德华多

【问题讨论】:

  • 从本质上讲,递归只不过是一种管理堆栈的便捷方式。任何可以通过递归实现的东西也可以通过显式管理的堆栈以非递归方式实现。在 Python 中,您可以使用列表作为堆栈。代码通常不那么清晰,但也不需要那么糟糕。每当您进行递归调用时,将恢复当前调用所需的状态推送到堆栈上。每当您要递归返回时,从堆栈中弹出并恢复该状态。
  • 将标准递归快速排序转换为使用堆栈管理其状态的快速排序应该是一个相当简单的练习。您需要保存下限和上限以及枢轴索引。然后你可以循环而不是递归。将边界设置为第一个分区、循环并恢复您的上下文。然后将边界设置为第二个分区、循环并恢复您的上下文。这就是您需要做的所有事情。
  • 另一种可能性是使用堆排序,它不需要递归或堆栈。它也是一个 O(n*log(n)) 排序算法。它的平均情况性能比快速排序稍差,但它的最坏情况性能仍然是 O(n*log(n)),不像快速排序在最坏情况下可能比 O(n*log(n)) 更差。

标签: python numpy sorting quicksort


【解决方案1】:

标准的 unix/linux qsort 是在没有递归的情况下实现的,以提高效率。你可以查一下,或者把这个答案中的代码翻译成python:

Can quicksort be implemented in C without stack and recursion?

【讨论】:

  • 该问题中所有发布的代码都使用堆栈(实际上,只有一个答案包含代码,并且明确提到它使用具有 1000 个元素的有界堆栈,实现为两个数组,并注释这是不可接受的)。另一方面,接受的答案引用了一篇声称不使用堆栈的论文,但帖子中没有代码。
  • 不。 chqrlie 的代码没有使用栈,没有问题。
  • beg[MAX_LEVELS]end[MAX_LEVELS] 都是用作堆栈的数组。该函数使用两个固定大小的数组,它们限制了它可以排序的最大数组的大小,并将它们用作堆栈。此外,它们都驻留在 调用堆栈 中,尽管这无关紧要。原始代码使用 1000 个元素的堆栈,海报修改为使用 64 个元素的堆栈。但在任何一种情况下,所需的堆栈数量都会随着输入数组的大小而增长,输入数组的大小基于实现中的固定大小堆栈。海报说得很清楚。
  • 关键是这些实现都没有像真正的 O(1) 实现那样扩展到任意大的输入数组。实际上,这可能无关紧要,但从算法的角度来看,它们不是 O(1),这是张贴者明确承认的事实。
【解决方案2】:

FWIW,这是 Python 版本:

# This function is same in both iterative and recursive
def partition(arr,l,h):
    i = ( l - 1 )
    x = arr[h]
  
    for j in range(l , h):
        if   arr[j] <= x:
  
            # increment index of smaller element
            i = i+1
            arr[i],arr[j] = arr[j],arr[i]
  
    arr[i+1],arr[h] = arr[h],arr[i+1]
    return (i+1)
  
# Function to do Quick sort
# arr[] --> Array to be sorted,
# l  --> Starting index,
# h  --> Ending index
def quickSortIterative(arr,l,h):
  
    # Create an auxiliary stack
    size = h - l + 1
    stack = [0] * (size)
  
    # initialize top of stack
    top = -1
  
    # push initial values of l and h to stack
    top = top + 1
    stack[top] = l
    top = top + 1
    stack[top] = h
  
    # Keep popping from stack while is not empty
    while top >= 0:
  
        # Pop h and l
        h = stack[top]
        top = top - 1
        l = stack[top]
        top = top - 1
  
        # Set pivot element at its correct position in
        # sorted array
        p = partition( arr, l, h )
  
        # If there are elements on left side of pivot,
        # then push left side to stack
        if p-1 > l:
            top = top + 1
            stack[top] = l
            top = top + 1
            stack[top] = p - 1
  
        # If there are elements on right side of pivot,
        # then push right side to stack
        if p+1 < h:
            top = top + 1
            stack[top] = p + 1
            top = top + 1
            stack[top] = h
  
# Driver code to test above
arr = [4, 3, 5, 2, 1, 3, 2, 3]
n = len(arr)
quickSortIterative(arr, 0, n-1)
print ("Sorted array is:")
for i in range(n):
    print ("%d" %arr[i])

【讨论】:

    猜你喜欢
    • 2020-04-18
    • 2019-11-16
    • 2017-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-14
    • 2021-12-31
    • 2021-06-26
    相关资源
    最近更新 更多