具有枢轴功能问题的QuickSort?

时间:2015-11-17 08:26:28

标签: python algorithm sorting quicksort

过去几个小时我一直在看这个,但仍然无法理解我搞砸了哪里。我一直在索引超出范围的错误,如下所示:

enter image description here

我完成的每个小编辑或更改都让我遇到了另一个错误,然后我在尝试简化代码后再回到这里。

def quickSort(alist):
    firstList = []
    secondList = []
    thirdList = []

    if(len(alist) > 1):
        #pivot = pivot_leftmost(alist)
        #pivot = pivot_best_of_three(alist)
        pivot = pivot_ninther(alist)
        #pivot = pivot_random(alist)

        for item in alist:
            if(item < pivot):
                firstList.append(item)
            if(item == pivot):
                secondList.append(item)
            if(item > pivot):
                thirdList.append(item)
        sortedList = quickSort(firstList) + secondList + quickSort(thirdList)
        return sortedList
    else:
        print("list:", alist)
        print("sorted, nothing to do") #debug
        print("") #debug
        return alist

def pivot_ninther(alist):
    listLength = int(len(alist))
    third = int(listLength / 3)

    leftList = alist[:third]
    midlist = alist[third:(third * 2)]
    lastlist = alist[(third * 2):(third * 3)]

    leftBest = pivot_best_of_three(leftList)
    midBest = pivot_best_of_three(midlist)
    lastBest = pivot_best_of_three(lastlist)

    pivots = [leftBest, midBest, lastBest]

    return pivot_best_of_three(pivots)

我很确定一副新鲜的眼睛很容易找到它,但我已经好好看了几个小时。谢谢!

更新:(我的Best_of_three功能)

def pivot_best_of_three(alist):
    leftmost = 0
    middle = int(len(alist) / 2)
    rightmost = len(alist) - 1

    if (alist[leftmost] <= alist[middle] <= alist[rightmost] or alist[rightmost] <= alist[middle] <= alist[leftmost]):
        return alist[middle]
    elif (alist[middle] <= alist[leftmost] <= alist[rightmost] or alist[rightmost] <= alist[leftmost] <= alist[middle]):
        return alist[leftmost]
    else:
        return alist[rightmost]

2 个答案:

答案 0 :(得分:2)

IndexError尝试查找零项目列表的pivot_best_of_three成员时,会发生rightmost。解决这个问题的简单方法就是不要传递这样的列表。 :)

以下是这些功能的略微修改版本。我已经使用各种长度的列表测试了这些版本,长度为零,并且它们似乎正常运行。

def pivot_ninther(alist):
    listLength = len(alist)
    if listLength < 3:
        return alist[0]

    third = listLength // 3
    leftList = alist[:third]
    midlist = alist[third:-third]
    lastlist = alist[-third:]

    leftBest = pivot_best_of_three(leftList)
    midBest = pivot_best_of_three(midlist)
    lastBest = pivot_best_of_three(lastlist)

    pivots = [leftBest, midBest, lastBest]

    return pivot_best_of_three(pivots)

def pivot_best_of_three(alist):
    leftmost = alist[0]
    middle = alist[len(alist) // 2]
    rightmost = alist[-1]

    if (leftmost <= middle <= rightmost) or (rightmost <= middle <= leftmost):
        return middle
    elif (middle <= leftmost <= rightmost) or (rightmost <= leftmost <= middle):
        return leftmost
    else:
        return rightmost

正如您所看到的,我简化了pivot_best_of_three,因此它不会为同一个值多次索引alist

但是可以使用简单的sorting network

进一步简化
def sort3(a, b, c):
    if c < b: b, c = c, b
    if b < a: a, b = b, a
    if c < b: b, c = c, b
    return a, b, c

def pivot_best_of_three(alist):
    leftmost = alist[0]
    middle = alist[len(alist) // 2]
    rightmost = alist[-1]
    return sort3(leftmost, middle, rightmost)[1]

答案 1 :(得分:0)

尝试较小的计数(&lt; = 20)并检查在第三次== 0(在最深的递归级别)时pivot_ninther()中会发生什么?似乎它会创建空数组,然后尝试索引它们。

在调用pivot_ninther()之前,代码应该检查以确保长度&gt; = 9,然后在调用... best_of_three()时检查&gt; = 3。如果只有一两件商品,请选一件。

建议,在让quicksort工作后,备份源代码而不是创建新数组,pivot函数应该与原始数组和第一个/中间/最后一个索引一起使用。

你可以使用掉期来简化中间值3.这有助于像逆序数组开始一样。

    // median of 3
    i = lo, j = (lo + hi)/2, k = hi;
    if (a[k] < a[i])
        swap(a[k], a[i]);
    if (a[j] < a[i])
        swap(a[j], a[i]);
    if (a[k] < a[j])
        swap(a[k], a[j]);
    pivot = a[j];

wiki文章:

http://en.wikipedia.org/wiki/Quicksort#Choice_of_pivot