Как работает алгоритм сортировки кучей?

Есть алгоритм сортировки кучей по возрастанию:

  1. Вставлять элементы, делая min-heap
  2. Удалять элементы (root), оставляя свойства

У меня есть вопросы к этому коду:

def heap_sort(arr, size):
    for i in range(size // 2 - 1, -1, -1):
        heapify(arr, size, i)

    for i in range(size - 1, 0, -1):
        arr[i], arr[0] = arr[0], arr[i]
        heapify(arr, i, 0)

    print(arr)


def heapify(array, size, index):
    done = False

    while not done:
        largest = index
        left = 2 * index + 1
        right = 2 * index + 2

        if left < size and array[largest] < array[left]:
            largest = left

        if right < size and array[largest] < array[right]:
            largest = right

        if largest != index:
            array[index], array[largest] = array[largest], array[index]
            index = largest
        else:
            done = True
  1. Как получается сортировка по возрастанию, если куча max-heap
  2. Я понимаю, что в heap_sort первый цикл строит кучу, второй удаляет элементы, знаю, как работает удаление и добавление в куче. Но я не понимаю, почему отсчет идет к концу с size // 2 - 1. Почему во втором цикле тоже идет отсчёт к концу
  3. Почему это все работает, если где-то пишут, что левый элемент считается по формуле 2i, а здесь 2i + 1. Я тестил свою сортировку кучей с 2i + 1 на левый элемент и все ломалось

При этом я не до конца понимаю условий в heapify. Буду благодарен, если кто-нибудь понятным языком и подробно объяснит, как работает алгоритм сверху


Ответы (1 шт):

Автор решения: MBo

1.. Вот эта операция

arr[i], arr[0] = arr[0], arr[i]

ставит вершину - наибольший элемент - в конец массива, затем остаток кучи (верхняя часть) восстанавливает свойства кучи, следующий максимум ставится вторым с конца и т.д., и в результате получается сортировка по возрастанию

2.. "Отсчёт" идёт к началу, за это отвечает шаг -1 в range. Почему с size // 2 - 1? - да потому что это индекс последнего родителя в куче, у элементов с большим номером нет деток.

3.. Левый элемент считается по формуле 2i, если индексация идёт с единицы, а здесь использована индексация с нуля.

→ Ссылка