Просеивание вниз в куче

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

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

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

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

Продолжаем сравнивать 16 с его дочерним узлом 15. Поскольку 16 больше, обмен сейчас не нужен. Наконец, наша операция просеивания вниз завершена, свойство максимальной кучи сохранено.

4. Пример кода на Java

Скачать исходный пакет:Скачать

Код файла src/example/heap/HeapShiftDown.java:

package example.heap;

/**
* Извлечь элемент из максимальной кучи
 */

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];
    }
}
Другие расширения