在python中以最后一个元素为轴实现QuickSort

时间:2018-10-30 23:42:07

标签: python quicksort

我似乎无法正确完成此操作。我在下面粘贴了我的代码。使用print语句,我认为正在发生的事情是第一遍的结果是作为答案返回的结果,尽管所有递归步骤都通过print显示了输出,表明它们正在按预期方式工作,但结果似乎没有保存?我试图就地执行此操作,但是只是修改了array [],但是我觉得这里有些误解。任何帮助表示赞赏。

键盘:http://codepad.org/jVMbbJTq

代码:

def quicksort(array):
    if len(array) >1:
        print "enter array", array
        pivot = len(array) - 1
        print "pivot", array[pivot]
        x = 0
        while x < pivot:
            if array[x]>array[pivot]:
                piv = array[pivot]
                xval = array[x]
                array[x] = array[pivot-1]
                array[pivot] = xval
                array[pivot-1] = piv
        #        temp = array[x]
         #       array[x] = array[pivot]
         #       array[pivot] = temp
               # array.append(array.pop(x))
                pivot -= 1
            else:
                x += 1
        print "pre recur split array", array
        print "left", array[:pivot]
        print "right", array[pivot+1:]
        quicksort(array[:pivot])
        quicksort(array[pivot+1:])
        print "post recur split array", array
    return array
test = [21, 4, 1, 3, 9, 20, 25, 6, 21, 14]
#test = [21, 4, 1, 3]
print quicksort(test)
print "answer", test

2 个答案:

答案 0 :(得分:1)

问题是quicksort(array[:pivot])quicksort(array[pivot+1:])不修改接收到的数组,它们返回排序后的数组。即使这样做,即使您调用带有切片列表作为参数的函数并在函数内部修改该参数,原始列表也不会受到影响。

一种解决算法的方法如下:

def quicksort(array):
    if len(array) >1:
        print "enter array", array
        pivot = len(array) - 1
        print "pivot", array[pivot]
        x = 0
        while x < pivot:
            if array[x]>array[pivot]:
                piv = array[pivot]
                xval = array[x]
                array[x] = array[pivot-1]
                array[pivot] = xval
                array[pivot-1] = piv
                pivot -= 1
            else:
                x += 1
        print "pre recur split array", array
        print "left", array[:pivot]
        print "right", array[pivot+1:]
        array = quicksort(array[:pivot]) + [array[pivot]] + quicksort(array[pivot+1:])
        print "post recur split array", array
    return array

我还将包括一个更加“ Pythonic”的实现,该实现使用filter函数获取分别低于和高于枢轴的元素列表。从本质上讲,这是您的解决方案使用的相同算法;但是比较干净。

def quick_sort(l):
    if len(l) > 1:
        # Get the last element
        pivot = l[-1]
        # Get a list of all the elements of l lower that the pivot
        lower = list(filter(lambda x: x < pivot, l))
        # Now the higher ones
        higher = list(filter(lambda x: x > pivot, l))
        l = quick_sort(lower) + [pivot] + quick_sort(higher)
    return l

答案 1 :(得分:1)

我不确定您的代码是否只有问题,但是您遇到的一个大问题是您的递归不会做任何有用的事情。也就是说,这两行对您没有帮助:

    quicksort(array[:pivot])
    quicksort(array[pivot+1:])

它们什么都不做的原因是您执行的切片将输入列表array中的数据复制到了新列表中。然后,递归调用尝试对复制的列表进行排序。递归排序根本不会更改原始列表,因此,如果忽略它们的返回值,则调用代码中的任何内容都不会改变。

有几种方法可以解决此问题。一个简单(但效率低下)的解决方法是将每个递归调用返回的值分配回原始列表的一部分:

    array[:pivot] = quicksort(array[:pivot])
    array[pivot+1:] = quicksort(array[pivot+1:])

但是,如果您要执行类似的操作,则在代码前面的分区步骤中使用临时列表可能会使所有内容更易于理解(如果要复制所有数据在递归过程中仍然如此。

这是一个非常快速且肮脏的快速排序,可以将内容复制一堆(因此效率不高):

def quicksort(array):
    if len(array) <= 1:
        return array
    pivot_val = array[-1]
    lower = [x for x in array if x < pivot_val]
    upper = [x for x in array if x > pivot_val]
    pivot_count = array.count(pivot)
    return quicksort(lower) + [pivot_val]*pivot_count + quicksort(upper)

另一种更有效的方法是避免制作数据的任何副本(这意味着不进行切片)。只需对所有内容进行排序,包括递归部分。为此,您需要能够在递归调用中传递额外的参数,以指定需要排序的索引范围。幸运的是,在Python中向函数添加可选参数很容易(另一个选择是拥有一个单独的帮助函数来处理所有递归)。

与上面的简单修补程序相比,这涉及到对代码的更多更改,因为您不能再使用len(array)作为应在何处找到枢轴(或告诉您何时完成递归)的指南。这是一个快速尝试,但是我可能会遇到错误1或其他一些需要调试的错误:

def quicksort(array, low=0, high=None):    # add optional arguments
    if high == None:
        high = len(array) - 1              # set high if it got the default
    if high - low > 0:
        pivot = high                       # use high and low to set up pivot and x
        x = low
        while x < pivot:
            if array[x]>array[pivot]:      # this part stays the same
                piv = array[pivot]
                xval = array[x]
                array[x] = array[pivot-1]
                array[pivot] = xval
                array[pivot-1] = piv
                pivot -= 1
            else:
                x += 1
        quicksort(array, low, pivot-1)     # pass on new high and low values
        quicksort(array, pivot+1, high)
    return array                           # you probably don't need this line any more

如果采用这种就地方法,则可能要摆脱函数的return array部分。运行的Python函数的标准是返回None(如果您没有任何return语句,则会发生这种情况)。您将熟悉许多这样的方法。例如,list.append不返回任何内容,list.sort(“官方”排序功能)也不返回。当修改传递给它们的列表时,标准库模块中的功能(例如random.shuffle也会返回None