Давайте сделаем это с очень простым примером построения максимальной кучи, который, я думаю, ответит на ваши вопросы.Представьте, что у вас есть массив [3, 1, 6, 4, 7, 9]
.Это соответствует этому двоичному дереву:
3
1 6
4 7 9
Идея алгоритма состоит в том, чтобы сдвинуть вещи в кучу на свое место.Ваш первый вопрос: почему мы начинаем с i = n//2
.Простой ответ заключается в том, что любой узел в положении, превышающем i // 2, является листом;у него нет детей, и поэтому его нельзя оттолкнуть.На самом деле, мы можем начать с (n-1)//2
, потому что если n
является четным, то существует первый неконечный узел, а для нечетного числа (n-1)//2 == n/2
.
Так что в этом случае i=2
.Ваш следующий вопрос: почему мы предполагаем, что элемент с индексом i
является самым большим.Мы неМы начнем с этого, потому что мы должны найти самый большой из трех предметов (предмет в i
и его двух дочерних элементах).Таким образом, мы просто по умолчанию i
.Вы можете, если хотите, установить largest
для левого потомка, а затем выполнить сравнения.Но нет особой причины делать это таким образом.Вы должны начать с что-то , и элемент с индексом i
является самым простым.
В этом случае элемент с индексом i
равен 6. Мы проверяем потомков элементаи обнаружим, что 9 больше, поэтому мы меняемся местами.Результат:
3
1 9
4 7 6
Мы уменьшаем i
, давая нам i=1
.Глядя на предмет там и его дочерние элементы, мы видим, что число 7 является самым большим, поэтому мы поменяли местами два элемента, получив:
3
7 9
4 1 6
И теперь мы в корне.9 является наибольшим среди корня и его потомков, поэтому мы поменяемся местами:
9
7 3
4 1 6
И вот ответ на ваш третий вопрос: почему рекурсивный вызов heapify
?Вы должны толкнуть предмет до кучи, насколько это возможно.Здесь 3 меньше 6, поэтому мы должны поменять местами эти элементы:
9
7 6
4 1 3