Просеивание вниз в куче
В этом разделе будет рассказано, как извлечь элемент из максимальной кучи — эта операция называется просеиванием вниз. Можно извлечь только элемент с наивысшим приоритетом, то есть корневой узел. После извлечения исходного 62 ниже объясняется, как заполнить эту максимальную кучу.

Первый шаг — поместить последний элемент массива в корневой узел. В этот момент он не удовлетворяет определению максимальной кучи.

Процесс корректировки заключается в перемещении этого корневого узла 16 вниз шаг за шагом. Поскольку 16 меньше обоих дочерних узлов, сначала сравним дочерние узлы 52 и 30, чтобы определить, какой из них больше, и поменяем местами с большим.

Продолжаем сравнивать дочерние узлы 16: 28 и 41. Поскольку 41 больше, 16 и 41 меняются местами.

Продолжаем сравнивать 16 с его дочерним узлом 15. Поскольку 16 больше, обмен сейчас не нужен. Наконец, наша операция просеивания вниз завершена, свойство максимальной кучи сохранено.
4. Пример кода на Java
Скачать исходный пакет:Скачать
Код файла src/example/heap/HeapShiftDown.java:
/**
* Извлечь элемент из максимальной кучи
*/
public class HeapShiftDown<T extends Comparable> {
protected T[] data;
protected int count;
protected int capacity;
// Конструктор, создаёт пустую кучу, которая может вместить capacity элементов
public HeapShiftDown(int capacity){
// Здесь +1 обозначает количество элементов, которое изначально может храниться; после удаления 0-й позиции он может вмещать только capacity элементов
data = (T[])new Comparable[capacity+1];
count = 0;
this.capacity = capacity;
}
// Вернуть количество элементов в куче
public int size(){
return count;
}
// Вернуть boolean, указывающий, пуста ли куча
public boolean isEmpty(){
return count == 0;
}
// Вставить новый элемент item в максимальную кучу
public void insert(T item){
assert count + 1 <= capacity;
data[count+1] = item;
count ++;
shiftUp(count);
}
// Извлечь верхний элемент из максимальной кучи, т.е. наибольшие данные, хранящиеся в куче
public T extractMax(){
assert count > 0;
T ret = data[1];
swap( 1 , count );
count --;
shiftDown(1);
return ret;
}
// Получить верхний элемент max-кучи
public T getMax(){
assert( count > 0 );
return data[1];
}
// Поменять местами два элемента с индексами i и j в куче
private void swap(int i, int j){
T t = data[i];
data[i] = data[j];
data[j] = t;
}
//********************
//* Основные вспомогательные функции max-кучи
//********************
private void shiftUp(int k){
while( k > 1 && data[k/2].compareTo(data[k]) < 0 ){
swap(k, k/2);
k /= 2;
}
}
// Операция shiftDown
private void shiftDown(int k){
while( 2*k <= count ){
int j = 2*k; // В этой итерации цикла data[k] и data[j] меняются местами
if( j+1 <= count && data[j+1].compareTo(data[j]) > 0 )
j ++;
// data[j] — максимум из data[2*k] и data[2*k+1]
if( data[k].compareTo(data[j]) >= 0 ) break;
swap(k, j);
k = j;
}
System.out.println("shiftDown завершён");
}
// Тест HeapShiftDown
public static void main(String[] args) {
HeapShiftDown<Integer> heapShiftDown = new HeapShiftDown<Integer>(100);
// Количество элементов в куче
int N = 100;
// Диапазон значений элементов кучи [0, M)
int M = 100;
for( int i = 0 ; i < N ; i ++ )
heapShiftDown.insert( new Integer((int)(Math.random() * M)) );
Integer[] arr = new Integer[N];
// Постепенно извлекаем данные из максимальной кучи с помощью extractMax
// Порядок извлечения должен быть от наибольшего к наименьшему
for( int i = 0 ; i < N ; i ++ ){
arr[i] = heapShiftDown.extractMax();
System.out.print(arr[i] + " ");
}
// Убедитесь, что массив arr отсортирован от наибольшего к наименьшему
for( int i = 1 ; i < N ; i ++ )
assert arr[i-1] >= arr[i];
}
}