Делаю Квиксорт для удовольствия, но есть что-то, чего я не понимаю


Просто хочу убедиться, что это не вопрос домашнего задания. Я делаю это просто для развлечения и, вероятно, для блога.

Я использую версию быстрой сортировки "на месте" в соответствии с этой Вики-страницей.

Вот код, который я написал:

# solution 2

def swap(arr, left, right):
    try:
        tmp = arr[left]
        arr[left] = arr[right]
        arr[right] = tmp
    except IndexError:
        print "!IndexError: left, right", left, right
        raise

def partition(arr, left, right, pindex):
    pivot = arr[pindex]
    swap(arr, right, pindex)
    npindex = left
    for i in range(left, right+1): # +1 so the last item is included
        if arr[i] < pivot:
            swap(arr, i, npindex)   
            npindex += 1
    swap(arr, npindex, right)
    return npindex

def qs(arr):
    qs2(arr, 0, len(arr)-1)
    return arr

def qs2(arr, left, right):
    if left < right:
        # midpoint = (right - left) / 2
        midpoint = left # this works.
        nindex = partition(arr, left, right, midpoint)
        qs2(arr, left, nindex-1)
        qs2(arr, nindex+1, right)

def test():
    test = [23, 45, 12, 1, 3, -9, 67, 122, 8, 2, 0]
    res = qs(list(test))
    print "startt", test
    print "endt", res

if __name__ == "__main__":
    test() 

Чего я не понимаю, так это того, что, согласно Википедии, выбор pivot (variable midpoint inside function qs2) может быть случайным, пока он находится в пределах.

Однако, если я просто возьму среднюю точку (т. е. (левая + правая) /2 ), то quicksort не работает. Используя значение left , он работает.

Я что-то упустил в понимании алгоритма?

EDIT : я только что понял, что в stackoverflow есть тег 'quicksort'. Если этот вопрос был задан раньше, примите мои извинения и, пожалуйста, дайте мне знать. Я закрою этот вопрос. Тем временем я рассматриваю эти вопросы с помощью тега quicksort

2 2

2 ответа:

Выбор элемента pivot также осложняется наличием переполнения целых чисел. Если граничные индексы сортируемого подмножества достаточно велики, наивное выражение для среднего индекса (левый + правый)/2 вызовет переполнение и предоставит недопустимый индекс разворота. Это можно преодолеть, используя, например, left + (right-left)/2 для индексации среднего элемента, ценой более сложной арифметики. Аналогичные проблемы возникают и в некоторых других методах выбора точки разворота элемент.

Это должно быть (left + right) / 2, а не (right - left) / 2. Википедия объясняет, что использование left + (right - left) / 2 позволяет избежать переполнения целых чисел.

У вас есть midpoint = (right - left) / 2. Я думаю, что вы имеете в виду (right + left) / 2, иначе ваша средняя точка находится за пределами заданных границ.